in-place algorithm and fix of perf bug where we not early exited in spsort after insertion sorting small buckets so they were sorted again by us too :-)

This commit is contained in:
Richard Thier 2022-08-16 18:06:46 +02:00
parent b1ab4f2f87
commit 36ea38940b

View File

@ -134,55 +134,39 @@ inline void spsort(uint32_t *t, int n, int m = 32);
/** Helper function that puts elements higher then mid to the top of the array and lower to the bottom. Returns number of bottoms */ /** Helper function that puts elements higher then mid to the top of the array and lower to the bottom. Returns number of bottoms */
inline int internal_array_separate(uint32_t *t, int n, uint32_t mid) { inline int internal_array_separate(uint32_t *t, int n, uint32_t mid) {
/* if(n > 0) {
// Init left-right "write head" indices // Two heads that also read & write (both)
int left = 0; int left = 0;
int right = n - 1; int right = n - 1;
uint32_t current = t[left]; while(left < right) {
bool current_is_left = true; bool lok = (t[left] < mid);
bool rok = (t[right] >= mid);
// Separate to the ends of the array (in-place) if(lok || rok) {
for(int i = 0; i < n; ++i) { // HOT PATH
if(current < mid) { // Move heads until both in wrong location
const auto tmp = t[left]; left += lok;
t[left++] = current; right -= rok;
current = current_is_left ? t[left] : tmp; } else {
current_is_left = true; // REGULAR PATH
// Both in wrong location - xchg them!
} else { auto tmp = t[right];
const auto tmp = t[right]; t[right] = t[left];
t[right--] = current; t[left] = tmp;
current = tmp; ++left;
current = !current_is_left ? t[right] : tmp; --right;
current_is_left = false; }
} }
// Edge-case increment if single elem happens in middle in the end
left += ((left == right) && (t[left] < mid));
return left;
} }
return left; return 0;
*/
// FIXME: bad quality debug code to remove
std::vector<uint32_t> v(n);
int left = 0;
int right = n - 1;
auto current = t[0];
for(int i = 0; i < n; ++i) {
if(current < mid) {
v[left++] = current;
current = t[i + 1];
} else {
v[right--] = current;
current = t[i + 1];
}
}
for(int i = 0; i < n; ++i) {
t[i] = v[i];
}
return left;
} }
// TODO: [spsort] In-place variant that looks like a quicksort-kind-of-thing: // ALGO: [spsort] In-place variant that looks like a quicksort-kind-of-thing:
// - I realized that in-placing make this similar to quicksort actually // - I realized that in-placing make this similar to quicksort actually
// - We check if the thing is small enough for insertion sorting in-place // - We check if the thing is small enough for insertion sorting in-place
// - If not, we calculate low-mid-high // - If not, we calculate low-mid-high
@ -205,6 +189,7 @@ inline void internal_spsort(uint32_t *t, int n, int m, uint32_t low, uint32_t mi
// Makes small arrays sort fast otherwise we need to go down m == 2 or such! // Makes small arrays sort fast otherwise we need to go down m == 2 or such!
if(n < m) { if(n < m) {
binsertion_sort(t, n); binsertion_sort(t, n);
return;
} }
auto left = internal_array_separate(t, n, mid); auto left = internal_array_separate(t, n, mid);