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);
|
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() {
|
int main() {
|
||||||
qs();
|
qs();
|
||||||
qsr();
|
qsr();
|
||||||
zss();
|
zss();
|
||||||
qs3();
|
qs3();
|
||||||
|
qs3_sp();
|
||||||
|
qs3_sp2();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
185
qsort.h
185
qsort.h
@ -2,6 +2,11 @@
|
|||||||
#ifndef MY_QUICKSORT_H
|
#ifndef MY_QUICKSORT_H
|
||||||
#define 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>
|
#include <stdint.h>
|
||||||
|
|
||||||
/* Uncomment for debugging with if(someevent) raise(SIGINT); */
|
/* 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)
|
* @returns The partition points, end of left and right (inclusive)
|
||||||
*/
|
*/
|
||||||
static inline pret3 partition3(uint32_t array[], int low, int high, uint32_t pivotval) {
|
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 */
|
/* index until smaller or eq elements lay */
|
||||||
int i = (low - 1);
|
int i = (low - 1);
|
||||||
uint32_t pc = 0;
|
uint32_t pc = 0;
|
||||||
|
|
||||||
/* traverse each element of the array */
|
/* traverse each element of the array */
|
||||||
/* compare them with the pivot */
|
/* compare them with the pivotval */
|
||||||
#pragma GCC unroll 4
|
#pragma GCC unroll 4
|
||||||
for (int j = low; j <= high; ++j) {
|
for (int j = low; j <= high; ++j) {
|
||||||
/* Branchless pivot-count */
|
/* Branchless pivot-count */
|
||||||
pc += (array[j] == pivot);
|
pc += (array[j] == pivotval);
|
||||||
|
|
||||||
if(array[j] < pivot) {
|
if(array[j] < pivotval) {
|
||||||
/* if element smaller than pivot is found */
|
/* if element smaller than pivotval is found */
|
||||||
/* swap it with the greater element pointed by i */
|
/* swap it with the greater element pointed by i */
|
||||||
++i;
|
++i;
|
||||||
|
|
||||||
@ -134,7 +136,7 @@ static inline pret3 partition3(uint32_t array[], int low, int high, uint32_t piv
|
|||||||
|
|
||||||
#pragma GCC unroll 4
|
#pragma GCC unroll 4
|
||||||
for (int j = high; j > i; --j) {
|
for (int j = high; j > i; --j) {
|
||||||
if (array[j] > pivot) {
|
if (array[j] > pivotval) {
|
||||||
/* if element smaller than pivot is found */
|
/* if element smaller than pivot is found */
|
||||||
/* swap it with the greater element pointed by i */
|
/* swap it with the greater element pointed by i */
|
||||||
--i2;
|
--i2;
|
||||||
@ -151,6 +153,138 @@ static inline pret3 partition3(uint32_t array[], int low, int high, uint32_t piv
|
|||||||
return ret;
|
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 */
|
/* 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 */
|
/* 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 */
|
/* ZSSORTC */
|
||||||
|
|
||||||
/** Always at most log(n) space needing randomized quicksort variant - with checking for sameconst-arrays */
|
/** Always at most log(n) space needing randomized quicksort variant - with checking for sameconst-arrays */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user