diff --git a/qs.c b/qs.c index 62895d6..94aa11c 100644 --- a/qs.c +++ b/qs.c @@ -43,7 +43,7 @@ void qsr() { printArray(data, n); } -// qs test function +// zss test function void zss() { #include "data.inc" @@ -56,9 +56,26 @@ void zss() { 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() { qs(); qsr(); zss(); + qs3(); return 0; } diff --git a/qsort.h b/qsort.h index 28839ee..177e9b4 100644 --- a/qsort.h +++ b/qsort.h @@ -10,8 +10,9 @@ /* Structure: * * - BASICS: Basic quicksort - * - EXTRAS: Extra quicksort and partitioning helpers (also random pick and pivot index picks). Basic (free) min-max search - * - PMINMAX: Partitioning with min-max searches in generated partitions + * - RANDOMPIV: Randomized pivoting and partitioning by given pivot-indexed element. + * - 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! */ @@ -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 @@ -106,6 +167,54 @@ static inline int partition_with_pivot(uint32_t array[], int pi, int low, int hi 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 * @@ -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); } -// 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 */ /** @@ -363,7 +443,7 @@ static inline int partition_with_pivotval(uint32_t array[], int low, int high, u swapit(&array[i], &array[j]); /* 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) { pivoti = i; leftmax = array[i];