threeway partitioning inplace quicksort

This commit is contained in:
Richard Thier 2025-04-08 00:37:58 +02:00
parent 32b5721e37
commit a465110170
2 changed files with 131 additions and 34 deletions

19
qs.c
View File

@ -43,7 +43,7 @@ void qsr() {
printArray(data, n); printArray(data, n);
} }
// qs test function // zss test function
void zss() { void zss() {
#include "data.inc" #include "data.inc"
@ -56,9 +56,26 @@ void zss() {
printArray(data, n); printArray(data, n);
} }
// qs3 test function
void qs3() {
#include "data.inc"
int n = sizeof(data) / sizeof(data[0]);
// memory junnnk is enough
rpivotstate rand;
// perform qs3 on data
quicksort_rand3(data, 0, n - 1, &rand);
printf("(qs3) Sorted array in ascending order: \n");
printArray(data, n);
}
int main() { int main() {
qs(); qs();
qsr(); qsr();
zss(); zss();
qs3();
return 0; return 0;
} }

146
qsort.h
View File

@ -10,8 +10,9 @@
/* Structure: /* Structure:
* *
* - BASICS: Basic quicksort * - BASICS: Basic quicksort
* - EXTRAS: Extra quicksort and partitioning helpers (also random pick and pivot index picks). Basic (free) min-max search * - RANDOMPIV: Randomized pivoting and partitioning by given pivot-indexed element.
* - PMINMAX: Partitioning with min-max searches in generated partitions * - MINMAX: partitioning while doing min-max over the whole + related extras.
* - PMINMAX: Partitioning with min-max searches in generated partitions + related.
* - VALPART: Partitioning by value - not by random or given pivot index! * - VALPART: Partitioning by value - not by random or given pivot index!
*/ */
@ -78,7 +79,67 @@ static inline void quicksort(uint32_t array[], int low, int high) {
} }
} }
/* EXTRAS */ /* THREEWAY */
struct pret3 {
int leftend;
int rightend;
};
typedef struct pret3 pret3;
/**
* Partition the array threeway by puutting ALL pivots to the middle and smaller/biggers left-right
*
* @param array The array to partition
* @param low From when. (inclusive)
* @param high Until when. (inclusive too!)
* @param pivotval This value is used to partition the array.
* @returns The partition points, end of left and right (inclusive)
*/
static inline pret3 partition3(uint32_t array[], int low, int high, uint32_t pivotval) {
/* select the rightmost element as pivot */
uint32_t pivot = pivotval;
/* index until smaller or eq elements lay */
int i = (low - 1);
/* traverse each element of the array */
/* compare them with the pivot */
#pragma GCC unroll 4
for (int j = low; j < high; ++j) {
if (array[j] < pivot) {
/* if element smaller than pivot is found */
/* swap it with the greater element pointed by i */
++i;
/* swap element at i with element at j */
swapit(&array[i], &array[j]);
}
}
/* index until smaller or eq elements lay */
int i2 = (high + 1);
#pragma GCC unroll 4
for (int j = high; j > i; --j) {
if (array[j] > pivot) {
/* if element smaller than pivot is found */
/* swap it with the greater element pointed by i */
--i2;
/* swap element at i with element at j */
swapit(&array[i2], &array[j]);
}
}
/* return the partition points */
pret3 ret;
ret.leftend = i;
ret.rightend = i2;
return ret;
}
/* RANDOMPIV */
/** /**
* Partition the array and using the pivot index * Partition the array and using the pivot index
@ -106,6 +167,54 @@ static inline int partition_with_pivot(uint32_t array[], int pi, int low, int hi
return partition(array, low, high); return partition(array, low, high);
} }
// 32-bit LCG for fast random generations
static inline uint32_t lcg(uint32_t *state) {
*state = *state * 1664525u + 1013904223u;
return *state;
}
/** Get pivot index in [0, len-1] without modulus - see our fastrand.h */
static inline uint32_t pick_pivot(uint32_t *state, uint32_t len) {
uint32_t rand = lcg(state);
/* Multiply by len, take the upper 32 bits of the 64-bit result */
return (uint32_t)(((uint64_t)rand * len) >> 32);
}
typedef uint32_t rpivotstate;
/** Randomized pivoting in-place recursive quicksort on array for elements in [low, high] indices */
static inline void quicksort_rand(uint32_t array[], int low, int high, rpivotstate *state) {
if (low < high) {
int pi = pick_pivot(state, (high + 1) - low) + low;
pi = partition_with_pivot(array, pi, low, high);
/* recursive call on the left of pivot */
quicksort_rand(array, low, pi - 1, state);
/* recursive call on the right of pivot */
quicksort_rand(array, pi + 1, high, state);
}
}
/* THREEWAY_RAND */
/** Randomized pivoting in-place recursive quicksort on array for elements in [low, high] indices */
static inline void quicksort_rand3(uint32_t array[], int low, int high, rpivotstate *state) {
if (low < high) {
/* partition threeway by random pivot */
int pi = pick_pivot(state, (high + 1) - low) + low;
pret3 res = partition3(array, low, high, array[pi]);
/* recursive call on the left of pivot */
quicksort_rand3(array, low, res.leftend, state);
/* recursive call on the right of pivot */
quicksort_rand3(array, res.rightend, high, state);
}
}
/* MINMAX */
/** /**
* Partition the array while doing a min-max search and find the pivot element such that * Partition the array while doing a min-max search and find the pivot element such that
* *
@ -184,35 +293,6 @@ static inline int partition_and_minmax_with_pivot(uint32_t array[], int pi, int
return partition_and_minmax(array, low, high, minout, maxout); return partition_and_minmax(array, low, high, minout, maxout);
} }
// 32-bit LCG for fast random generations
static inline uint32_t lcg(uint32_t *state) {
*state = *state * 1664525u + 1013904223u;
return *state;
}
/** Get pivot index in [0, len-1] without modulus - see our fastrand.h */
static inline uint32_t pick_pivot(uint32_t *state, uint32_t len) {
uint32_t rand = lcg(state);
/* Multiply by len, take the upper 32 bits of the 64-bit result */
return (uint32_t)(((uint64_t)rand * len) >> 32);
}
typedef uint32_t rpivotstate;
/** Randomized pivoting in-place recursive quicksort on array for elements in [low, high] indices */
static inline void quicksort_rand(uint32_t array[], int low, int high, rpivotstate *state) {
if (low < high) {
int pi = pick_pivot(state, (high + 1) - low) + low;
pi = partition_with_pivot(array, pi, low, high);
/* recursive call on the left of pivot */
quicksort_rand(array, low, pi - 1, state);
/* recursive call on the right of pivot */
quicksort_rand(array, pi + 1, high, state);
}
}
/* PMINMAX */ /* PMINMAX */
/** /**
@ -363,7 +443,7 @@ static inline int partition_with_pivotval(uint32_t array[], int low, int high, u
swapit(&array[i], &array[j]); swapit(&array[i], &array[j]);
/* After this, array[i] can never change - so we can save it as a found pivot-index */ /* After this, array[i] can never change - so we can save it as a found pivot-index */
/* Min-search on elements by telling which is closest to pivotval by abs difference! */ /* Max-search on elements by telling which is closest to pivotval by abs difference! */
if(array[i] > leftmax) { if(array[i] > leftmax) {
pivoti = i; pivoti = i;
leftmax = array[i]; leftmax = array[i];