104 lines
3.3 KiB
C
104 lines
3.3 KiB
C
#ifndef INCLUDED_C_QUICKSORTITERATIVE_H
|
|||
|
|
#define INCLUDED_C_QUICKSORTITERATIVE_H
|
||
|
|
|
||
|
|
#ifndef INCLUDED_C_BASE_H
|
||
|
|
#include <c_Base.h>
|
||
|
|
#endif /*INCLUDED_C_BASE_H*/
|
||
|
|
|
||
|
|
|
||
|
|
#ifndef INCLUDED_C_MEMORY_H
|
||
|
|
#include <c_Memory.h>
|
||
|
|
#endif /*INCLUDED_C_MEMORY_H*/
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Internal macro helper to swap two arbitrary blocks of memory.
|
||
|
|
*/
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Standard Lomuto or Hoare-style tracking partition loop.
|
||
|
|
* Uses the rightmost element as the pivot for flat linear execution.
|
||
|
|
*/
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
long long c_PartitionIterative(char* arr, long long left, long long right, c_size_t size,
|
||
|
|
void* temp, int (*compar)(const void*, const void*)) {
|
||
|
|
char* pivot = arr + (right * size);
|
||
|
|
long long i = left - 1;
|
||
|
|
|
||
|
|
for (long long j = left; j < right; j++) {
|
||
|
|
if (compar(arr + (j * size), pivot) <= 0) {
|
||
|
|
i++;
|
||
|
|
c_SwapInternal(arr + (i * size), arr + (j * size), size, temp);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
c_SwapInternal(arr + ((i + 1) * size), arr + (right * size), size, temp);
|
||
|
|
return (i + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Top-Level Custom Framework Entry Point for Non-Recursive Quicksort.
|
||
|
|
* Time Complexity: O(n log n) average | Space Complexity: O(log n) explicit stack | Stable: No
|
||
|
|
*/
|
||
|
|
C_STATIC_FORCE_INLINE
|
||
|
|
void c_QuickSortIterative(void* base, c_size_t num, c_size_t size,
|
||
|
|
int (*compar)(const void*, const void*)) {
|
||
|
|
if (base == NULL || num < 2 || size == 0) return;
|
||
|
|
|
||
|
|
char* arr = (char*)base;
|
||
|
|
|
||
|
|
// Optimization: Stack buffer allocation for pivot element swaps
|
||
|
|
#define QSORT_STACK_LIMIT 128
|
||
|
|
char stack_buf[QSORT_STACK_LIMIT];
|
||
|
|
void* temp = (size <= QSORT_STACK_LIMIT) ? stack_buf : C_ALLOC(size);
|
||
|
|
if (temp == NULL) return;
|
||
|
|
|
||
|
|
// Allocate the explicit partition boundary stack.
|
||
|
|
// Max required stack depth for range tracking is 2 * ceil(log2(num)) + 2.
|
||
|
|
// For a 64-bit address space, 128 slots safely handles any possible array size.
|
||
|
|
long long range_stack[128];
|
||
|
|
long long top = -1;
|
||
|
|
|
||
|
|
// Push initial array boundaries onto the tracking stack
|
||
|
|
range_stack[++top] = 0;
|
||
|
|
range_stack[++top] = (long long)num - 1;
|
||
|
|
|
||
|
|
// Keep processing partitions until the explicit boundary stack is empty
|
||
|
|
while (top >= 0) {
|
||
|
|
// Pop right and left boundaries
|
||
|
|
long long right = range_stack[top--];
|
||
|
|
long long left = range_stack[top--];
|
||
|
|
|
||
|
|
// Execute linear pivot segmentation
|
||
|
|
long long p = c_PartitionIterative(arr, left, right, size, temp, compar);
|
||
|
|
|
||
|
|
// If there are elements on the left side of the pivot, push their range to the stack
|
||
|
|
if (p - 1 > left) {
|
||
|
|
range_stack[++top] = left;
|
||
|
|
range_stack[++top] = p - 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// If there are elements on the right side of the pivot, push their range to the stack
|
||
|
|
if (p + 1 < right) {
|
||
|
|
range_stack[++top] = p + 1;
|
||
|
|
range_stack[++top] = right;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (size > QSORT_STACK_LIMIT) {
|
||
|
|
C_FREE(temp);
|
||
|
|
}
|
||
|
|
#undef QSORT_STACK_LIMIT
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
#endif /*INCLUDED_C_QUICKSORTITERATIVE_H*/
|