85 lines
2.9 KiB
C
85 lines
2.9 KiB
C
#include <c_QuickSort.h>
|
|||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Internal macro helper to swap two arbitrary blocks of memory of given size.
|
||
|
|
*/
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void c_SwapInternal(char* a, char* b, c_size_t size, void* temp) {
|
||
|
|
if (a == b) return;
|
||
|
|
memcpy(temp, a, size);
|
||
|
|
memcpy(a, b, size);
|
||
|
|
memcpy(b, temp, size);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Chooses the median of left, center, and right elements as the pivot,
|
||
|
|
* hides it at (right - 1), and returns a pointer to it.
|
||
|
|
*/
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void* c_MedianOfThree(char* arr, long long left, long long right, c_size_t size,
|
||
|
|
void* temp, int (*compar)(const void*, const void*)) {
|
||
|
|
long long center = left + (right - left) / 2;
|
||
|
|
|
||
|
|
// Order left, center, right
|
||
|
|
if (compar(arr + (left * size), arr + (center * size)) > 0) {
|
||
|
|
c_SwapInternal(arr + (left * size), arr + (center * size), size, temp);
|
||
|
|
}
|
||
|
|
if (compar(arr + (left * size), arr + (right * size)) > 0) {
|
||
|
|
c_SwapInternal(arr + (left * size), arr + (right * size), size, temp);
|
||
|
|
}
|
||
|
|
if (compar(arr + (center * size), arr + (right * size)) > 0) {
|
||
|
|
c_SwapInternal(arr + (center * size), arr + (right * size), size, temp);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Place pivot at position (right - 1)
|
||
|
|
c_SwapInternal(arr + (center * size), arr + ((right - 1) * size), size, temp);
|
||
|
|
return arr + ((right - 1) * size);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
void c_QuickSortSub(char* arr, long long left, long long right, c_size_t size, void* temp,
|
||
|
|
int (*compar)(const void*, const void*)) {
|
||
|
|
// Optimization: Fallback to manual insertion sort for tiny arrays to prune deep recursion
|
||
|
|
if (left + 10 > right) {
|
||
|
|
// Basic Inline Insertion Sort boundary loop
|
||
|
|
for (long long i = left + 1; i <= right; i++) {
|
||
|
|
memcpy(temp, arr + (i * size), size);
|
||
|
|
long long j = i;
|
||
|
|
while (j > left && compar(arr + ((j - 1) * size), temp) > 0) {
|
||
|
|
memcpy(arr + (j * size), arr + ((j - 1) * size), size);
|
||
|
|
j--;
|
||
|
|
}
|
||
|
|
memcpy(arr + (j * size), temp, size);
|
||
|
|
}
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Retrieve Median Pivot
|
||
|
|
c_MedianOfThree(arr, left, right, size, temp, compar);
|
||
|
|
|
||
|
|
long long i = left;
|
||
|
|
long long j = right - 1;
|
||
|
|
|
||
|
|
// Hoare Partitioning Loop
|
||
|
|
while (1) {
|
||
|
|
while (compar(arr + ((++i) * size), arr + ((right - 1) * size)) < 0);
|
||
|
|
while (compar(arr + ((--j) * size), arr + ((right - 1) * size)) > 0);
|
||
|
|
if (i < j) {
|
||
|
|
c_SwapInternal(arr + (i * size), arr + (j * size), size, temp);
|
||
|
|
} else {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Restore pivot to its correct final slot
|
||
|
|
c_SwapInternal(arr + (i * size), arr + ((right - 1) * size), size, temp);
|
||
|
|
|
||
|
|
// Recursively execute left and right segments
|
||
|
|
c_QuickSortSub(arr, left, i - 1, size, temp, compar);
|
||
|
|
c_QuickSortSub(arr, i + 1, right, size, temp, compar);
|
||
|
|
}
|