fixes to partitioning with pivot values - also simplified algorithm probably even faster actually because no avg calculation now
This commit is contained in:
parent
22bb267000
commit
69adbe4ae9
42
qsort.h
42
qsort.h
@ -15,13 +15,6 @@
|
||||
* - VALPART: Partitioning by value - not by random or given pivot index!
|
||||
*/
|
||||
|
||||
/** Hand-coded abs difference - I wanted to minimize dependencies by not needing stdlib.h */
|
||||
static inline int64_t absdiff(uint32_t a, uint32_t b) {
|
||||
/* Should be branchless and fast */
|
||||
int64_t n = (a - b);
|
||||
return (n > 0) ? n : -n;
|
||||
}
|
||||
|
||||
/* BASICS */
|
||||
|
||||
/** Swap operation */
|
||||
@ -228,11 +221,15 @@ static inline void quicksort_rand(uint32_t array[], int low, int high, rpivotsta
|
||||
* - Elements smaller than pivot are on left of pivot
|
||||
* - Elements greater than pivot are on right of pivot
|
||||
*
|
||||
* (***): The left min-max outputs can return not just the left partition, but left partition ++ pivotpoint region min-max!
|
||||
* This does not only happen if partition is empty, but also when pivot was already highest and last earlier.
|
||||
* Would be hard to handle this edge-case and min-max out is generally used as output hints only so I prefer speed..
|
||||
*
|
||||
* @param array The array to partition
|
||||
* @param low From when. (inclusive)
|
||||
* @param high Until when. (inclusive too!)
|
||||
* @param minout_left OUT: Will be filled with the minimum key of left partition or pivot value when partition empty
|
||||
* @param maxout_left OUT: Will be filled with the maximum key of left partition or pivot value when partition empty
|
||||
* @param minout_left OUT: Will be filled with the minimum key of left partition or pivot value when partition empty. Also (***)
|
||||
* @param maxout_left OUT: Will be filled with the maximum key of left partition or pivot value when partition empty. Also (***)
|
||||
* @param minout_right OUT: Will be filled with the minimum key of right partition or pivot value when partition empty
|
||||
* @param maxout_right OUT: Will be filled with the maximum key of right partition or pivot value when partition empty
|
||||
* @returns The partition point.
|
||||
@ -320,7 +317,7 @@ static inline int partition_and_pminmax_with_pivot(
|
||||
/* swap pivot with rightmost */
|
||||
swapit(&array[high], &array[pi]);
|
||||
/* delegate to previous sol. */
|
||||
return partition_and_pminmax(array, low, high, minout_left, maxout_left, maxout_left, maxout_right);
|
||||
return partition_and_pminmax(array, low, high, minout_left, maxout_left, minout_right, maxout_right);
|
||||
}
|
||||
|
||||
/* VALPART */
|
||||
@ -328,14 +325,15 @@ static inline int partition_and_pminmax_with_pivot(
|
||||
/**
|
||||
* Partition the array using pivot value - and find pivot closest to that value (and place them at proper pivot index)
|
||||
*
|
||||
* - Elements smaller than pivot are on left of pivot
|
||||
* - Elements greater than pivot are on right of pivot
|
||||
* - The "pivot" element we have found is the closest to the "pivotval" given.
|
||||
* - Elements smaller-eq than pivotval are on left of pivot
|
||||
* - Elements greater than pivotval are on right of pivot
|
||||
* - The "pivot" element we find is the biggest among the ones smaller-eq to the pivot value
|
||||
* or if there is no such (all is greater) we return first greater-than value index (right[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 - pivot will be the closest to this valued element!
|
||||
* @param pivotval This value is used to partition the array.
|
||||
* @returns The partition point.
|
||||
*/
|
||||
static inline int partition_with_pivotval(uint32_t array[], int low, int high, uint32_t pivotval) {
|
||||
@ -343,7 +341,7 @@ static inline int partition_with_pivotval(uint32_t array[], int low, int high, u
|
||||
|
||||
/* Select the rightmost element as pivot just because */
|
||||
/* Need some start-value for min(abs(pv - p)) search! */
|
||||
int64_t mindiff = absdiff(array[low], pivotval);
|
||||
int64_t leftmax = -1;
|
||||
/* Index of currently found pivot value */
|
||||
uint32_t pivoti = low;
|
||||
|
||||
@ -366,17 +364,23 @@ static inline int partition_with_pivotval(uint32_t array[], int low, int high, u
|
||||
|
||||
/* 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! */
|
||||
int64_t diff = absdiff(array[i], pivotval);
|
||||
pivoti = (diff < mindiff) ? i : pivoti;
|
||||
if(array[i] > leftmax) {
|
||||
pivoti = i;
|
||||
leftmax = array[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Must check if above loop found elem at all - because its guessing */
|
||||
if(i != (low - 1)) {
|
||||
// TODO: Remove debug stuff
|
||||
printf("array[%d]: %d <---> %d :array[%d] @ pivotval: %u\n", i, array[i], array[pivoti], pivoti, pivotval);
|
||||
if(pivotval == 2147494598u) raise(SIGINT);
|
||||
printf("array:i[%d:i]: %d <---> %d :array:pivoti[%d] @ pivotval: %u && [%u..%u]\n",
|
||||
i, array[i], array[pivoti], pivoti, pivotval, low, high);
|
||||
|
||||
/* swap the pivot element into its place */
|
||||
swapit(&array[i], &array[pivoti]);
|
||||
} else printf("array:i[%d:i]: %d <-/-> %d :array:pivoti[%d] @ pivotval: %u && [%u..%u]\n",
|
||||
i, array[i], array[pivoti], pivoti, pivotval, low, high);
|
||||
|
||||
/* return the partition point: index of pivot element */
|
||||
return i;
|
||||
|
Loading…
x
Reference in New Issue
Block a user