2025-04-05 02:15:39 +02:00
# ifndef ZS_SORT_H
# define ZS_SORT_H
2025-04-07 02:38:28 +02:00
/*
* 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
*/
2025-04-05 02:15:39 +02:00
# include <stdint.h>
# include "qsort.h"
2025-04-07 02:38:28 +02:00
/* ZSSORT */
2025-04-05 03:35:21 +02:00
/** Always at most log(n) space needing quicksort variant */
2025-04-05 02:15:39 +02:00
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! */
}
}
}
2025-04-07 02:38:28 +02:00
/* ZSSORT */
2025-04-05 03:35:21 +02:00
/** Always at most log(n) space needing randomized quicksort variant */
2025-04-05 02:15:39 +02:00
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! */
}
}
}
2025-04-07 02:38:28 +02:00
/* ZSSORTC */
2025-04-05 03:35:21 +02:00
/** 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 ) ;
}
}
}
2025-04-07 02:38:28 +02:00
/* 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 */
2025-04-05 03:35:21 +02:00
2025-04-07 02:38:28 +02:00
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 ) ;
2025-04-05 03:35:21 +02:00
2025-04-07 02:38:28 +02:00
/* 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.
2025-04-05 03:35:21 +02:00
2025-04-05 02:15:39 +02:00
# endif /* ZS_SORT_H */