#ifndef ZS_SORT_H #define ZS_SORT_H /* * Structure: * - ZSSORT: The at most log(n) space needing quicksort * - RZSSORT: Randomized pivoting variant at most log(n) space needing quicksort * - RZSSORTC: Added check for fully same value const array (also randomized pivot) * - MEANQS: Randomized pivoting AND pivoting based on min-max range - dual recursive */ #include #include "qsort.h" /* ZSSORT */ /** Always at most log(n) space needing quicksort variant */ static inline void zssort(uint32_t array[], int low, int high) { /* (*) Loop handles original "other half recursion"! */ while(low < high) { int pi = partition(array, low, high); /* If we recurse only the smaller part */ /* That ensures at most n/2 elements can */ /* be on any given level of the recursion */ /* tree: that is we ensure log2(N) memuse! */ if((pi - low) < (high - pi)) { // Left smaller: recurse left of pivot zssort(array, low, pi - 1); // (*) Update partitioning loop for remaining part low = pi + 1; } else { // Right smaller: recurse right of pivot zssort(array, pi + 1, high); // (*) Update partitioning loop for remaining part high = pi - 1; /* high inclusive! */ } } } /* ZSSORT */ /** Always at most log(n) space needing randomized quicksort variant */ static inline void zssort_rand(uint32_t array[], int low, int high, rpivotstate *state) { while (low < high) { int pi = pick_pivot(state, (high + 1) - low) + low; pi = partition_with_pivot(array, pi, low, high); /* If we recurse only the smaller part */ /* That ensures at most n/2 elements can */ /* be on any given level of the recursion */ /* tree: that is we ensure log2(N) memuse! */ if((pi - low) < (high - pi)) { // Left smaller: recurse left of pivot zssort_rand(array, low, pi - 1, state); // (*) Update partitioning loop for remaining part low = pi + 1; } else { // Right smaller: recurse right of pivot zssort_rand(array, pi + 1, high, state); // (*) Update partitioning loop for remaining part high = pi - 1; /* high inclusive! */ } } } /* ZSSORTC */ /** Always at most log(n) space needing randomized quicksort variant - with checking for sameconst-arrays */ static inline void zsrc(uint32_t array[], int low, int high, rpivotstate *state) { if (low < high) { uint32_t min, max; int pi = pick_pivot(state, (high + 1) - low) + low; pi = partition_and_minmax_with_pivot(array, pi, low, high, &min, &max); if(min != max) { /* Recursion with zssort_rand ensures logn+1 stack spacen need! */ zssort_rand(array, low, pi - 1, state); zssort_rand(array, pi + 1, high, state); } } } /* MEANQS */ /** * Rangsort entry point and outer-recursive function of meanqs. * * We pick a random pivot, but in the meantime try to quess mean for next level partitioning. * This and meanqs_inner is co-recursive (call each other) * * @param array The array to sort * @param low From when. (inclusive) * @param high Until when. (inclusive too!) * @param state The random pivot picking state */ static inline void meanqs(uint32_t array[], int low, int high, rpivotstate *state); /** * Inner-recursive function of meanqs - calls meanqs() as next level recursion. * * @param array The array to sort * @param low From when. (inclusive) * @param high Until when. (inclusive too!) * @param pivotval We first partition to smaller-eq/bigger than pivotval, later we might pick random though * @param state The random pivot picking state */ static inline void meanqs_inter(uint32_t array[], int low, int high, uint32_t pivotval, rpivotstate *state) { /* First: partition using pivot val + recurse */ if (low < high) { /* For the first level, use the pivotval they provide */ /* This only helps somewhat, because below loop.... */ /* ..But code it better if you can do consistently! */ int pi = partition_with_pivotval(array, low, high, pivotval); /* If we recurse only the smaller part */ /* That ensures at most n/2 elements can */ /* be on any given level of the recursion */ /* tree: that is we ensure log2(N) memuse! */ if((pi - low) < (high - pi)) { // Left smaller: recurse left of pivot meanqs(array, low, pi - 1, state); // (*) Update partitioning loop for remaining part low = pi + 1; } else { // Right smaller: recurse right of pivot meanqs(array, pi + 1, high, state); // (*) Update partitioning loop for remaining part high = pi - 1; /* high inclusive! */ } } /* Later: picking random pivot and partition like that */ /* (*) Rem.: The above if can be understood as different first iteration of this while loop... */ while (low < high) { /* Random picking here - no info anymore about mean */ int pi = pick_pivot(state, (high + 1) - low) + low; pi = partition_with_pivot(array, pi, low, high); /* If we recurse only the smaller part */ /* That ensures at most n/2 elements can */ /* be on any given level of the recursion */ /* tree: that is we ensure log2(N) memuse! */ if((pi - low) < (high - pi)) { // Left smaller: recurse left of pivot meanqs(array, low, pi - 1, state); // (*) Update partitioning loop for remaining part low = pi + 1; } else { // Right smaller: recurse right of pivot meanqs(array, pi + 1, high, state); // (*) Update partitioning loop for remaining part high = pi - 1; /* high inclusive! */ } } } /** * Rangsort entry point and outer-recursive function of meanqs. * * We pick a random pivot, but in the meantime try to quess mean for next level partitioning. * This and meanqs_inner is co-recursive (call each other) * * @param array The array to sort * @param low From when. (inclusive) * @param high Until when. (inclusive too!) * @param state The random pivot picking state */ static inline void meanqs(uint32_t array[], int low, int high, rpivotstate *state) { if (low < high) { uint32_t lmin, lmax, rmin, rmax; int pi = pick_pivot(state, (high + 1) - low) + low; pi = partition_and_pminmax_with_pivot(array, pi, low, high, &lmin, &lmax, &rmin, &rmax); /* These also handle constant (always same valued) subarrays */ if(lmin != lmax) { /* Better than (a+b)/2 avg because of overflow possibilities */ uint32_t lavg = lmin + (lmax - lmin) / 2; /* Recursion with inter "ensures" logn stack spacen need! */ meanqs_inter(array, low, pi - 1, lavg, state); } if(rmin != rmax) { /* Better than (a+b)/2 avg because of overflow possibilities */ uint32_t ravg = rmin + (rmax - rmin) / 2; /* Recursion with inter "ensures" logn stack spacen need! */ meanqs_inter(array, pi + 1, high, ravg, state); } } } // TODO: Idea: Quadratic time happens when you repeatedly pick pivots close to the maximum or minimum - so why not re-pick near extremals being picked which now can be cheked? I think we should have a treshold - maybe dynamically set by first minmax - and logarithmically divide the treshold by 2 in case its still too close the next randomization time. This handles smallrange badly though. #endif /* ZS_SORT_H */