spsort got twovalue sort special case (no infinite recursion)
This commit is contained in:
parent
6a0a2540bb
commit
edbb59d7a1
@ -63,6 +63,63 @@ void binsertion_sort(uint32_t *a, int n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Specific sort that sorts arrays that can only have two or one different values (but many of those). O(n) strictly linear! */
|
||||||
|
void twovalue_sort(uint32_t *t, int n) {
|
||||||
|
if(n > 0) {
|
||||||
|
// Prepare for counting
|
||||||
|
uint32_t v1 = t[0];
|
||||||
|
bool has_v2 = false;
|
||||||
|
uint32_t v2;
|
||||||
|
int c1 = 0;
|
||||||
|
int c2 = 0;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
// Find second value (if there is any) and stop there
|
||||||
|
while((i < n) && !has_v2) {
|
||||||
|
has_v2 = (t[i] != v1);
|
||||||
|
v2 = t[i]; // can be junk, but only used when has_v2 == true!
|
||||||
|
c1 += !has_v2;
|
||||||
|
c2 += has_v2;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This only works for numbers from now on...
|
||||||
|
// But if we keep all until this point, we can
|
||||||
|
// do a similar "xchg to the sides" trick here
|
||||||
|
// by knowing which value is smaller and thus
|
||||||
|
// code this to work generally if needed!
|
||||||
|
|
||||||
|
// Finish counting loop
|
||||||
|
while(i < n) {
|
||||||
|
c1 += (v1 == t[i]); // count v1s
|
||||||
|
c2 += has_v2 ? (v2 == t[i]) : 0;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have counts of value variants, just write them back
|
||||||
|
|
||||||
|
// Get which is the smaller value and how many there is?
|
||||||
|
int sv = has_v2 ? ((v2 < v1) ? v2 : v1): v1;
|
||||||
|
int sc = has_v2 ? ((v2 < v1) ? c2 : c1): c1;
|
||||||
|
|
||||||
|
// Write out the smaller values
|
||||||
|
i = 0;
|
||||||
|
while(i < sc) {
|
||||||
|
t[i] = sv;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write out the big values for all remaining places
|
||||||
|
if(i < n) {
|
||||||
|
int bv = has_v2 ? ((v2 >= v1) ? v2 : v1): v1;
|
||||||
|
while(i < n) {
|
||||||
|
t[i] = bv;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Overflow-safe and generally safe */
|
/** Overflow-safe and generally safe */
|
||||||
inline uint32_t internal_mid(uint32_t low, uint32_t high) {
|
inline uint32_t internal_mid(uint32_t low, uint32_t high) {
|
||||||
/* Unsigned-ness make this overflow-safe */
|
/* Unsigned-ness make this overflow-safe */
|
||||||
@ -166,7 +223,7 @@ inline void internal_spsort(uint32_t *t, int n, int m, uint32_t low, uint32_t mi
|
|||||||
// means we can small-sort both.
|
// means we can small-sort both.
|
||||||
binsertion_sort(t + left, rights);
|
binsertion_sort(t + left, rights);
|
||||||
} else {
|
} else {
|
||||||
// RE-PIVOT!!!
|
// RE-PIVOT!!! [right]
|
||||||
// This tries to help for cases where the
|
// This tries to help for cases where the
|
||||||
// domain of da values have a few outliers
|
// domain of da values have a few outliers
|
||||||
// which would cause many unnecessity split.
|
// which would cause many unnecessity split.
|
||||||
@ -174,7 +231,23 @@ inline void internal_spsort(uint32_t *t, int n, int m, uint32_t low, uint32_t mi
|
|||||||
// This way the midpoint and all totally get
|
// This way the midpoint and all totally get
|
||||||
// re-evaluated too, which adds an O(n) here
|
// re-evaluated too, which adds an O(n) here
|
||||||
// but make us have fewer extra steps hopefully.
|
// but make us have fewer extra steps hopefully.
|
||||||
|
if(lefts != 0) {
|
||||||
|
// Regular case (left had some elements at least)
|
||||||
spsort(t + left, rights, m);
|
spsort(t + left, rights, m);
|
||||||
|
} else {
|
||||||
|
// Extreme case where left was empty!
|
||||||
|
// This would lead to endless recursion
|
||||||
|
// so we need to handle this separately!
|
||||||
|
//
|
||||||
|
// When left is totally empty that means
|
||||||
|
// that right bucket can only have at most
|
||||||
|
// two distict values among its elements or
|
||||||
|
// less (that is it is either const values
|
||||||
|
// in a big array OR there are two different
|
||||||
|
// values in it in any ways). For this we
|
||||||
|
// implemented a special and optimized sort...
|
||||||
|
twovalue_sort(t + left, rights); // O(n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// lefts are enough in count
|
// lefts are enough in count
|
||||||
@ -182,7 +255,7 @@ inline void internal_spsort(uint32_t *t, int n, int m, uint32_t low, uint32_t mi
|
|||||||
// if rights are too few, we insertion sort them
|
// if rights are too few, we insertion sort them
|
||||||
binsertion_sort(t + left, rights);
|
binsertion_sort(t + left, rights);
|
||||||
|
|
||||||
// RE-PIVOT!!!
|
// RE-PIVOT!!! [left]
|
||||||
// and we also need repivot similar to above!
|
// and we also need repivot similar to above!
|
||||||
spsort(t, lefts, m);
|
spsort(t, lefts, m);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user