added three-way single pass partitioning codes, they are a bit slower than the two-pass 3-way partitioning on my machine, but sp2 gets very close in performance so might be tweaked to get it be better maybe
This commit is contained in:
parent
12d30a588a
commit
5d6ea0e778
32
qs.c
32
qs.c
@ -72,10 +72,42 @@ void qs3() {
|
||||
printArray(data, n);
|
||||
}
|
||||
|
||||
void qs3_sp() {
|
||||
#include "data.inc"
|
||||
|
||||
int n = sizeof(data) / sizeof(data[0]);
|
||||
|
||||
// memory junnnk is enough
|
||||
rpivotstate rand;
|
||||
|
||||
// perform qs3 on data
|
||||
quicksort_rand3_sp(data, 0, n - 1, &rand);
|
||||
|
||||
printf("(qs3_sp) Sorted array in ascending order: \n");
|
||||
printArray(data, n);
|
||||
}
|
||||
|
||||
void qs3_sp2() {
|
||||
#include "data.inc"
|
||||
|
||||
int n = sizeof(data) / sizeof(data[0]);
|
||||
|
||||
// memory junnnk is enough
|
||||
rpivotstate rand;
|
||||
|
||||
// perform qs3 on data
|
||||
quicksort_rand3_sp2(data, 0, n - 1, &rand);
|
||||
|
||||
printf("(qs3_sp2) Sorted array in ascending order: \n");
|
||||
printArray(data, n);
|
||||
}
|
||||
|
||||
int main() {
|
||||
qs();
|
||||
qsr();
|
||||
zss();
|
||||
qs3();
|
||||
qs3_sp();
|
||||
qs3_sp2();
|
||||
return 0;
|
||||
}
|
||||
|
185
qsort.h
185
qsort.h
@ -2,6 +2,11 @@
|
||||
#ifndef MY_QUICKSORT_H
|
||||
#define MY_QUICKSORT_H
|
||||
|
||||
/* Used in quicksort_rand3_sp under which we call regular quicksort_rand3 without singlepassing */
|
||||
#ifndef RAND3_SP_VAL
|
||||
#define RAND3_SP_VAL 64
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Uncomment for debugging with if(someevent) raise(SIGINT); */
|
||||
@ -97,22 +102,19 @@ typedef struct pret3 pret3;
|
||||
* @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);
|
||||
uint32_t pc = 0;
|
||||
|
||||
/* traverse each element of the array */
|
||||
/* compare them with the pivot */
|
||||
/* compare them with the pivotval */
|
||||
#pragma GCC unroll 4
|
||||
for (int j = low; j <= high; ++j) {
|
||||
/* Branchless pivot-count */
|
||||
pc += (array[j] == pivot);
|
||||
pc += (array[j] == pivotval);
|
||||
|
||||
if(array[j] < pivot) {
|
||||
/* if element smaller than pivot is found */
|
||||
if(array[j] < pivotval) {
|
||||
/* if element smaller than pivotval is found */
|
||||
/* swap it with the greater element pointed by i */
|
||||
++i;
|
||||
|
||||
@ -134,7 +136,7 @@ static inline pret3 partition3(uint32_t array[], int low, int high, uint32_t piv
|
||||
|
||||
#pragma GCC unroll 4
|
||||
for (int j = high; j > i; --j) {
|
||||
if (array[j] > pivot) {
|
||||
if (array[j] > pivotval) {
|
||||
/* if element smaller than pivot is found */
|
||||
/* swap it with the greater element pointed by i */
|
||||
--i2;
|
||||
@ -151,6 +153,138 @@ static inline pret3 partition3(uint32_t array[], int low, int high, uint32_t piv
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Partition the array threeway by puutting ALL pivots to the middle and smaller/biggers left-right.
|
||||
* Single-pass version.
|
||||
*
|
||||
* @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_sp(uint32_t array[], int low, int high, uint32_t pivotval) {
|
||||
|
||||
/* Invariant for left: index until smaller (than pivot) elements lay */
|
||||
int il = (low - 1);
|
||||
/* Invariant for right: index until (from top) bigger elements lay */
|
||||
int ir = (high + 1);
|
||||
/* Indices from where we swap left and right into "is" (and sometimes swap among here too) */
|
||||
int jl = low;
|
||||
int jr = high;
|
||||
|
||||
while(jl <= jr) {
|
||||
/* Jump through any pivot elements */
|
||||
while((array[jl] == pivotval) && (jl < high)) ++jl;
|
||||
while((array[jr] == pivotval) && (jr > low)) --jr;
|
||||
if(jl > jr) break;
|
||||
|
||||
if(array[jl] < pivotval) {
|
||||
/* if element smaller than pivotval is found */
|
||||
/* swap it with the element pointed by i */
|
||||
++il;
|
||||
if(il != jl) swapit(&array[il], &array[jl]);
|
||||
} else {
|
||||
/* Here its sure a[jl] and a[jr] are not pivots */
|
||||
/* Which means array[jl] > pivotval and on left */
|
||||
|
||||
if(array[jr] < pivotval) {
|
||||
/* We can totally safely just swap them */
|
||||
/* Because both are in wrong places.... */
|
||||
swapit(&array[jl], &array[jr]);
|
||||
/* swap it with the element pointed by i */
|
||||
++il;
|
||||
if(il != jl) swapit(&array[il], &array[jl]);
|
||||
} else {
|
||||
/* Left->right move needed, but right is */
|
||||
/* at good place already so handle that! */
|
||||
/* ensured: if(array[jr] > pivotval) */
|
||||
|
||||
/* Progress invariants */
|
||||
/* swap with the element pointed by i */
|
||||
--ir;
|
||||
if(ir != jr) swapit(&array[ir], &array[jr]);
|
||||
/* Because of swap we might swaped in pivot! */
|
||||
/* So continue our loop but do not step jl! */
|
||||
/* ++jl; // incomplete so no step! */
|
||||
--jr; /* STEP RIGHT because "continue"! */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Step left being processed */
|
||||
++jl;
|
||||
|
||||
if(array[jr] > pivotval) {
|
||||
/* if element bigger than pivotval is found */
|
||||
/* swap it with the element pointed by i */
|
||||
--ir;
|
||||
if(ir != jr) swapit(&array[ir], &array[jr]);
|
||||
} else {
|
||||
/* On wrong side - so we just need to look */
|
||||
/* for left-wrong-sided to swap it with! */
|
||||
continue; /* I think no ++jl needed! */
|
||||
}
|
||||
/* Step right being processed */
|
||||
--jr;
|
||||
}
|
||||
|
||||
/* return the partition points */
|
||||
pret3 ret;
|
||||
ret.leftend = il;
|
||||
ret.rightend = ir;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Partition the array threeway by puutting ALL pivots to the middle and smaller/biggers left-right.
|
||||
* Single-pass version 2.0
|
||||
*
|
||||
* @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_sp2(uint32_t array[], int low, int high, uint32_t pivotval) {
|
||||
|
||||
/* Invariant for left: index until smaller (than pivot) elements lay */
|
||||
int il = (low - 1);
|
||||
/* Invariant for right: index until (from top) bigger elements lay */
|
||||
int ir = (high + 1);
|
||||
/* Indices from where we swap left and right into "is" (and sometimes swap among here too) */
|
||||
int jl = low;
|
||||
int jr = high;
|
||||
|
||||
while(jl <= jr) {
|
||||
/* Handle left and find wrongly placed element */
|
||||
while((array[jl] <= pivotval) && (jl <= jr)) {
|
||||
if(array[jl] != pivotval) {
|
||||
if(++il != jl)
|
||||
swapit(&array[il], &array[jl]);
|
||||
}
|
||||
++jl;
|
||||
}
|
||||
|
||||
/* Handle right and find wrongly placed element */
|
||||
while((array[jr] >= pivotval) && (jl <= jr)) {
|
||||
if(array[jr] != pivotval) {
|
||||
if(--ir != jr)
|
||||
swapit(&array[ir], &array[jr]);
|
||||
}
|
||||
--jr;
|
||||
}
|
||||
|
||||
/* Swap the two found elements that are wrongly placed */
|
||||
if(jl < jr) swapit(&array[jl], &array[jr]);
|
||||
}
|
||||
|
||||
/* return the partition points */
|
||||
pret3 ret;
|
||||
ret.leftend = il;
|
||||
ret.rightend = ir;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* RANDOMPIV */
|
||||
|
||||
/**
|
||||
@ -225,6 +359,41 @@ static inline void quicksort_rand3(uint32_t array[], int low, int high, rpivotst
|
||||
}
|
||||
}
|
||||
|
||||
/** Randomized pivoting in-place recursive quicksort on array for elements in [low, high] indices */
|
||||
static inline void quicksort_rand3_sp(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;
|
||||
if(high - low > RAND3_SP_VAL) res = partition3_sp(array, low, high, array[pi]);
|
||||
else res = partition3(array, low, high, array[pi]);
|
||||
|
||||
/* recursive call on the left of pivot */
|
||||
quicksort_rand3_sp(array, low, res.leftend, state);
|
||||
|
||||
/* recursive call on the right of pivot */
|
||||
quicksort_rand3_sp(array, res.rightend, high, state);
|
||||
}
|
||||
}
|
||||
|
||||
/** Randomized pivoting in-place recursive quicksort on array for elements in [low, high] indices */
|
||||
static inline void quicksort_rand3_sp2(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;
|
||||
res = partition3_sp2(array, low, high, array[pi]);
|
||||
/* if(high - low > RAND3_SP_VAL) res = partition3_sp2(array, low, high, array[pi]);
|
||||
else res = partition3(array, low, high, array[pi]); */
|
||||
|
||||
/* recursive call on the left of pivot */
|
||||
quicksort_rand3_sp2(array, low, res.leftend, state);
|
||||
|
||||
/* recursive call on the right of pivot */
|
||||
quicksort_rand3_sp2(array, res.rightend, high, state);
|
||||
}
|
||||
}
|
||||
|
||||
/* MINMAX */
|
||||
|
||||
/**
|
||||
|
53
zssort.h
53
zssort.h
@ -89,6 +89,59 @@ static inline void zssort_rand3(uint32_t array[], int low, int high, rpivotstate
|
||||
}
|
||||
}
|
||||
|
||||
/** Always at most log(n) space needing randomized quicksort variant */
|
||||
static inline void zssort_rand3_sp(uint32_t array[], int low, int high, rpivotstate *state) {
|
||||
while (low < high) {
|
||||
int pi = pick_pivot(state, (high + 1) - low) + low;
|
||||
pret3 res;
|
||||
if(high - low > RAND3_SP_VAL) res = partition3_sp(array, low, high, array[pi]);
|
||||
else res = partition3(array, low, high, array[pi]);
|
||||
|
||||
/* 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((res.leftend - low) < (high - res.rightend)) {
|
||||
// Left smaller: recurse left of pivot
|
||||
zssort_rand3_sp(array, low, res.leftend, state);
|
||||
// (*) Update partitioning loop for remaining part
|
||||
low = res.rightend;
|
||||
} else {
|
||||
// Right smaller: recurse right of pivot
|
||||
zssort_rand3_sp(array, res.rightend, high, state);
|
||||
// (*) Update partitioning loop for remaining part
|
||||
high = res.leftend; /* high inclusive! */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Always at most log(n) space needing randomized quicksort variant */
|
||||
static inline void zssort_rand3_sp2(uint32_t array[], int low, int high, rpivotstate *state) {
|
||||
while (low < high) {
|
||||
int pi = pick_pivot(state, (high + 1) - low) + low;
|
||||
pret3 res;
|
||||
res = partition3_sp2(array, low, high, array[pi]);
|
||||
/*if(high - low > RAND3_SP_VAL) res = partition3_sp(array, low, high, array[pi]);
|
||||
else res = partition3(array, low, high, array[pi]);*/
|
||||
|
||||
/* 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((res.leftend - low) < (high - res.rightend)) {
|
||||
// Left smaller: recurse left of pivot
|
||||
zssort_rand3_sp2(array, low, res.leftend, state);
|
||||
// (*) Update partitioning loop for remaining part
|
||||
low = res.rightend;
|
||||
} else {
|
||||
// Right smaller: recurse right of pivot
|
||||
zssort_rand3_sp2(array, res.rightend, high, state);
|
||||
// (*) Update partitioning loop for remaining part
|
||||
high = res.leftend; /* high inclusive! */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ZSSORTC */
|
||||
|
||||
/** Always at most log(n) space needing randomized quicksort variant - with checking for sameconst-arrays */
|
||||
|
Loading…
x
Reference in New Issue
Block a user