minmax partitioning - maybe should support avg or dual-output-minmaxing too?
This commit is contained in:
parent
6fd6dbfff3
commit
f15cc423d2
81
qsort.h
81
qsort.h
@ -28,6 +28,7 @@ static inline void swapit(uint32_t *a, uint32_t *b) {
|
||||
* @param array The array to partition
|
||||
* @param low From when. (inclusive)
|
||||
* @param high Until when. (inclusive too!)
|
||||
* @returns The partition point.
|
||||
*/
|
||||
static inline int partition(uint32_t array[], int low, int high) {
|
||||
/* This is "Lomuto"s unidirectional partitioner - see algorithms book */
|
||||
@ -85,6 +86,7 @@ static inline void quicksort(uint32_t array[], int low, int high) {
|
||||
* @param pi The index of the pivot element to use. 0 or high is what OG quicksorts do.
|
||||
* @param low From when. (inclusive)
|
||||
* @param high Until when. (inclusive too!)
|
||||
* @returns The partition point.
|
||||
*/
|
||||
static inline int partition_with_pivot(uint32_t array[], int pi, int low, int high) {
|
||||
/*
|
||||
@ -100,6 +102,85 @@ static inline int partition_with_pivot(uint32_t array[], int pi, int low, int hi
|
||||
return partition(array, low, high);
|
||||
}
|
||||
|
||||
/**
|
||||
* Partition the array while doing a min-max search and find the pivot element such that
|
||||
*
|
||||
* - Elements smaller than pivot are on left of pivot
|
||||
* - Elements greater than pivot are on right of pivot
|
||||
*
|
||||
* @param array The array to partition
|
||||
* @param low From when. (inclusive)
|
||||
* @param high Until when. (inclusive too!)
|
||||
* @param minout OUT: Will be filled with the minimum key
|
||||
* @param maxout OUT: Will be filled with the maximum key
|
||||
* @returns The partition point.
|
||||
*/
|
||||
static inline int partition_and_minmax(uint32_t array[], int low, int high, uint32_t *minout, uint32_t *maxout) {
|
||||
/* This is "Lomuto"s unidirectional partitioner - see algorithms book */
|
||||
|
||||
/* select the rightmost element as pivot */
|
||||
uint32_t pivot = array[high];
|
||||
*minout = pivot;
|
||||
*maxout = pivot;
|
||||
|
||||
/* 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) {
|
||||
/* Branchless min-max */
|
||||
*minout = array[j] < *minout ? array[j] : *minout;
|
||||
*maxout = array[j] > *maxout ? array[j] : *maxout;
|
||||
|
||||
/* Lomuto partitioning */
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
/* swap the pivot element with the greater element at i */
|
||||
swapit(&array[i + 1], &array[high]);
|
||||
|
||||
/* return the partition point */
|
||||
return (i + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Partition the array and min-max and using the pivot index
|
||||
*
|
||||
* - Elements smaller than pivot are on left of pivot
|
||||
* - Elements greater than pivot are on right of pivot
|
||||
*
|
||||
* @param array The array to partition
|
||||
* @param pi The index of the pivot element to use. 0 or high is what OG quicksorts do.
|
||||
* @param low From when. (inclusive)
|
||||
* @param high Until when. (inclusive too!)
|
||||
* @param minout OUT: Will be filled with the minimum key
|
||||
* @param maxout OUT: Will be filled with the maximum key
|
||||
* @returns The partition point.
|
||||
*/
|
||||
static inline int partition_and_minmax_with_pivot(uint32_t array[], int pi, int low, int high, uint32_t *minout, uint32_t *maxout) {
|
||||
/*
|
||||
* Rem.: This looks like overhead,
|
||||
* but after seriously considering
|
||||
* writing the whole out I can tell
|
||||
* this is still fastests basically.
|
||||
*/
|
||||
|
||||
/* swap pivot with rightmost */
|
||||
swapit(&array[high], &array[pi]);
|
||||
/* delegate to previous sol. */
|
||||
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;
|
||||
|
26
zssort.h
26
zssort.h
@ -4,6 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include "qsort.h"
|
||||
|
||||
/** Always at most log(n) space needing quicksort variant */
|
||||
static inline void zssort(uint32_t array[], int low, int high) {
|
||||
/* (*) Loop handles original "other half recursion"! */
|
||||
while(low < high) {
|
||||
@ -27,6 +28,7 @@ static inline void zssort(uint32_t array[], int low, int high) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Always at most log(n) space needing randomized quicksort variant */
|
||||
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;
|
||||
@ -50,4 +52,28 @@ static inline void zssort_rand(uint32_t array[], int low, int high, rpivotstate
|
||||
}
|
||||
}
|
||||
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
// TODO: Guess the pivot value by previous min-maxes and let us use it inn partitioning (which would lead to "closest to pivot value" being swapped to its right position to keep the left:pivot:right separation architecture. Maybe can be faster than rand, although our randoms are pretty darn fast as you can see.
|
||||
|
||||
// TODO: Hackzolt éjféli ötlet:
|
||||
// - Particionálás min-max-avgleft-el
|
||||
// - két irányba rekurzió, bal oldalinak avgleft átadása, másik sima zssort_rand
|
||||
// - avgleft-es rekurzióból visszahívás ennek a jelenleginek a fő függvényére (ide-oda típusú rekurzió!)
|
||||
// - esetleg ha megéri, akkor avgright kiszámítása is jó lehet: drágább műveletek, de jobb algoritmus... hmmm
|
||||
|
||||
#endif /* ZS_SORT_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user