From 69adbe4ae94429053ce6747f25213192ccaea3c4 Mon Sep 17 00:00:00 2001 From: Richard Thier Date: Mon, 7 Apr 2025 04:58:18 +0200 Subject: [PATCH] fixes to partitioning with pivot values - also simplified algorithm probably even faster actually because no avg calculation now --- qsort.h | 48 ++++++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/qsort.h b/qsort.h index 0850b7a..045a9f9 100644 --- a/qsort.h +++ b/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]; + } } } - // 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); + /* Must check if above loop found elem at all - because its guessing */ + if(i != (low - 1)) { + // TODO: Remove debug stuff + 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]); + /* 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;