Files
cKit/Sort/c_QuickSort.c
2026-08-30 22:24:45 +08:00

480 lines
18 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <c_QuickSort.h>
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
#include <string.h>
/**
* @brief 原子操作:泛型就地物理内存块交换
*/
/**
* @brief 彻底加固的泛型物理内存块互换接口(256字节自适应滑窗,绝不踩踏)
*/
C_STATIC_FORCE_INLINE
void c_QS_Swap(void* a, void* b, c_size_t size) {
if (a == b || size == 0) return;
char* p1 = (char*)a;
char* p2 = (char*)b;
char temp_buf[256];
c_size_t bytes_left = size;
while (bytes_left > 0) {
c_size_t chunk = (bytes_left < sizeof(temp_buf)) ? bytes_left : sizeof(temp_buf);
memcpy(temp_buf, p1, chunk);
memcpy(p1, p2, chunk);
memcpy(p2, temp_buf, chunk);
p1 += chunk;
p2 += chunk;
bytes_left -= chunk;
}
}
/**
* @brief 最直观的 Lomuto 单路划分递归核心(完全规避 c_size_t 下溢)
*/
static void c_QuickSortRecursive(char* array_base, c_size_t low, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) {
// 递归终止:区间无元素或仅剩 1 个元素时安全返回
if (low >= high) {
return;
}
// 1. Lomuto 划分核心:选取当前区间的最后一个元素作为基准点 (Pivot)
char* pivot = array_base + (high * size);
// i 记录的是“小于基准点的元素”的右边界
c_size_t i = low;
// j 游标从 low 开始单调递增扫描到 high - 1
for (c_size_t j = low; j < high; j++) {
// 如果当前元素比基准点小,就把她跟 i 位置的数据互换,并将 i 向右推一步
if (cmp(array_base + (j * size), pivot, args) < 0) {
c_QS_Swap(array_base + (i * size), array_base + (j * size), size);
i++;
}
}
// 最后,将处于 high 位置的基准点本身,交换到边界 i 的地方归位
c_QS_Swap(array_base + (i * size), pivot, size);
// 此时绝对位置 i 处的元素已经各就各位。接下来两侧递归分治:
// 左半区:[low, i-1] | 右半区:[i+1, high]
// 核心安全防护:只有 i > 0 且 i - 1 > low 时才执行左半区减法,彻底封死无符号下溢
if (i > 0 && (i - 1) > low) {
c_QuickSortRecursive(array_base, low, i - 1, size, cmp, args);
}
// 只有 i + 1 < high 时才执行右半区加法,防止整数溢出
if (i < high) {
c_QuickSortRecursive(array_base, i + 1, high, size, cmp, args);
}
}
/**
* @brief 迭代版本泛型快速排序标准入口
*/
void c_QuickSort_Recursive(void* base, c_size_t num, c_size_t size, c_SortCompare_t cmp, void* args) {
if (!base || num < 2 || size == 0 || !cmp) {
return;
}
char* array_base = (char*)base;
// 闭区间从 0 开始到 num - 1。经过前置 num >= 2 的拦截,num - 1 绝对不会下溢
c_QuickSortRecursive(array_base, 0, num - 1, size, cmp, args);
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
/**
* @brief Dijkstra 三路划分标准安全控制流
*/
static void c_QuickSort3WayRecursive(char* array_base, c_size_t low, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) {
if (low >= high) {
return;
}
// 🌟【终极加固核心】:在局部栈上开辟只读缓冲区,将原始枢轴的内容完整镜像拷贝出来!
// 256字节支持绝大多数基础数据类型与中小型业务结构体
char pivot_buf[size];
memcpy(pivot_buf, array_base + (low * size), size);
c_size_t lt = low; // lt 维护小于 pivot 区间的右边界
c_size_t i = low + 1; // i 为当前单调递增扫描指针
c_size_t gt = high; // gt 维护大于 pivot 区间的左边界
while (i <= gt) {
char* item_i = array_base + (i * size);
// 🌟【核心修正】:后续所有的比对,全部投喂只读的临时影子副本 pivot_buf,
// 彻底绝缘由于首位数据被物理 Swap 覆盖导致的基准值污染!
int cmp_res = cmp(item_i, pivot_buf, args);
if (cmp_res < 0) {
c_QS_Swap(array_base + (lt * size), item_i, size);
lt++;
i++;
}
else if (cmp_res > 0) {
c_QS_Swap(item_i, array_base + (gt * size), size);
if (gt == i) {
break;
}
gt--;
}
else {
i++;
}
}
// -----------------------------------------------------------------
// 纯单调递增分治:隔离无符号整数下溢
// -----------------------------------------------------------------
if (lt > low) {
c_size_t left_high = lt - 1;
if (low < left_high) {
c_QuickSort3WayRecursive(array_base, low, left_high, size, cmp, args);
}
}
if (gt < high) {
c_QuickSort3WayRecursive(array_base, gt + 1, high, size, cmp, args);
}
}
/**
* @brief 对外标准标准入口
*/
void c_QuickSort_3Way(void* base, c_size_t num, c_size_t size, c_SortCompare_t cmp, void* args) {
if (!base || num < 2 || size == 0 || !cmp) {
return;
}
char* array_base = (char*)base;
c_QuickSort3WayRecursive(array_base, 0, num - 1, size, cmp, args);
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
#define COMPONENT_QS_CUTOFF 15
/**
* @brief 局部内联优化的泛型插入排序(供快排小区间降级调用)
*/
static void c_OptQS_InsertionSort(char* base, c_size_t low, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) {
for (c_size_t i = low + 1; i <= high; i++) {
c_size_t j = i;
char* item_i = base + (i * size);
char v_buf[256];
memcpy(v_buf, item_i, size);
while (j > low) {
char* current = base + (j * size);
char* previous = base + ((j - 1) * size);
if (cmp(v_buf, previous, args) < 0) {
memcpy(current, previous, size);
j--;
} else {
break;
}
}
memcpy(base + (j * size), v_buf, size);
}
}
/**
* @brief 三数取中(Median-of-Three)预处理逻辑
*
* 对首、中、尾三处元素进行就地排序,并将中位数物理挪动到区间最左侧(low 位置)充当主轴
*/
static void c_OptQS_MedianOfThree(char* base, c_size_t low, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) {
c_size_t mid = low + ((high - low) >> 1);
char* E_low = base + (low * size);
char* E_mid = base + (mid * size);
char* E_high = base + (high * size);
if (cmp(E_mid, E_low, args) < 0) c_QS_Swap(E_mid, E_low, size);
if (cmp(E_high, E_low, args) < 0) c_QS_Swap(E_high, E_low, size);
if (cmp(E_mid, E_high, args) < 0) c_QS_Swap(E_mid, E_high, size);
// 此时首尾中三点已升序,将作为中位数的 E_high 与 E_low 交换,确保枢轴位于起点
c_QS_Swap(E_low, E_high, size);
}
/**
* @brief 经典 Hoare 双路划分与递归核心(纯加法单调驱动,规避下溢)
*/
static void c_OptQuickSortRecursive(char* array_base, c_size_t low, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) {
// 优化点 1:小数组自适应截断降级
if (high - low < COMPONENT_QS_CUTOFF) {
c_OptQS_InsertionSort(array_base, low, high, size, cmp, args);
return;
}
// 优化点 2:激活三数取中,粉碎倒序或已排序序列的退化隐患
c_OptQS_MedianOfThree(array_base, low, high, size, cmp, args);
// 🌟 影子副本加固:将选取出的中位数枢轴数据复制到只读栈空间,绝缘交换别名污染!
char pivot_buf[size];
memcpy(pivot_buf, array_base + (low * size), size);
// Hoare 划分指针双向逼近控制
c_size_t i = low;
c_size_t j = high + 1; // 开区间初始边界
while (1) {
// 左指针 i 向右单调逼近,直到遇到大于或等于枢轴的元素才停止
do {
i++;
} while (i <= high && cmp(array_base + (i * size), pivot_buf, args) < 0);
// 右指针 j 向左单调收缩,直到遇到小于或等于枢轴的元素才停止
do {
j--;
} while (j >= low && cmp(array_base + (j * size), pivot_buf, args) > 0);
// 如果双向指针交叉,说明本次划分区域完全合拢
if (i >= j) {
break;
}
// 强行物理对调 i 和 j 处的元素(把大数顶到右边,小数挪到左边)
c_QS_Swap(array_base + (i * size), array_base + (j * size), size);
}
// 将驻留在 low 位置的枢轴元素与分界点 j 的元素进行对调归位
c_QS_Swap(array_base + (low * size), array_base + (j * size), size);
// -----------------------------------------------------------------
// 优化点 3:纯加法约束的分治控制,阻断无符号整数减法下溢
// -----------------------------------------------------------------
if (j > low) {
c_size_t left_high = j - 1;
if (low < left_high) {
c_OptQuickSortRecursive(array_base, low, left_high, size, cmp, args);
}
}
if (j < high) {
c_OptQuickSortRecursive(array_base, j + 1, high, size, cmp, args);
}
}
/**
* @brief 工业级三层优化双路快速排序标准对外入口
*/
void c_QuickSort_2Way_Optimized(void* base, c_size_t num, c_size_t size, c_SortCompare_t cmp, void* args) {
if (!base || num < 2 || size == 0 || !cmp) {
return;
}
char* array_base = (char*)base;
c_OptQuickSortRecursive(array_base, 0, num - 1, size, cmp, args);
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
/**
* @brief 内部辅助:获取两个无符号数中的较小值
*/
C_STATIC_FORCE_INLINE
c_size_t c_BM_Min(c_size_t a, c_size_t b) {
return (a < b) ? a : b;
}
/**
* @brief Bentley-McIlroy 三路划分与递归控制核心(完全规避 c_size_t 下溢)
*/
static void c_QuickBentleyMcIlroyRecursive(char* array_base, c_size_t low, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) {
if (low >= high) {
return;
}
// 🌟 影子副本加固:将当前首位元素拷贝到局部栈缓冲区,绝缘数据别名覆盖污染
char pivot_buf[size];
memcpy(pivot_buf, array_base + (low * size), size);
// 声明游标与边界控制(采用开区间或前置递增边界控制)
c_size_t i = low;
c_size_t j = high + 1;
c_size_t p = low; // p 维护左侧等于区的右边界
c_size_t q = high + 1; // q 维护右侧等于区的左边界
while (1) {
// 1. 左游标 i 向右单调扫描,遇到大于或等于枢轴的元素时停止
do {
i++;
} while (i <= high && cmp(array_base + (i * size), pivot_buf, args) < 0);
// 2. 右游标 j 向左单调收缩,遇到小于或等于枢轴的元素时停止
do {
j--;
} while (j >= low && cmp(array_base + (j * size), pivot_buf, args) > 0);
// 如果指针发生重合或交叉,说明中间两路扫描完全汇合
if (i >= j) {
break;
}
// 3. 交换 i 和 j 处的乱序元素(基础双路快排动作)
c_QS_Swap(array_base + (i * size), array_base + (j * size), size);
// 4. 【Bentley-McIlroy 核心拓展】:
// 如果换到左边的新元素恰好等于枢轴,将其物理顶推暂存到数组“最左端(p位置)”
if (cmp(array_base + (i * size), pivot_buf, args) == 0) {
p++;
c_QS_Swap(array_base + (p * size), array_base + (i * size), size);
}
// 如果换到右边的新元素恰好等于枢轴,将其物理顶推暂存到数组“最右端(--q位置)”
if (cmp(array_base + (j * size), pivot_buf, args) == 0) {
q--;
c_QS_Swap(array_base + (q * size), array_base + (j * size), size);
}
}
// 5. 特殊边界重对齐:如果相遇在等于区元素上,使 i 跨过分界点
if (i == j && cmp(array_base + (i * size), pivot_buf, args) == 0) {
i++;
if (j > 0) j--;
}
// 6. 【数据归位阶段】:将两端暂存的所有等于元素整体交换回正中央
// 把左端 [low, p] 的等于元素完美换回当前分界点 j 的左侧
c_size_t left_len = p - low + 1;
c_size_t left_move = (j >= low) ? (j - low + 1) : 0;
c_size_t num_to_swap_left = c_BM_Min(left_len, left_move);
for (c_size_t k = 0; k < num_to_swap_left; k++) {
c_QS_Swap(array_base + ((low + k) * size), array_base + ((j - k) * size), size);
}
// 把右端 [q, high] 的等于元素完美换回当前分界点 i 的右侧
c_size_t right_len = high - q + 1;
c_size_t right_move = (high >= i) ? (high - i + 1) : 0;
c_size_t num_to_swap_right = c_BM_Min(right_len, right_move);
for (c_size_t k = 0; k < num_to_swap_right; k++) {
c_QS_Swap(array_base + ((high - k) * size), array_base + ((i + k) * size), size);
}
// -----------------------------------------------------------------
// 7. 纯加法单调控制分治,隔离无符号整数下溢
// 此时中央区全部由等于元素接管,我们需要向外侧递归两端的小于区与大于区:
// 小于区:[low, j - num_to_swap_left] | 大于区:[i + num_to_swap_right, high]
// -----------------------------------------------------------------
if (j >= low && j >= num_to_swap_left) {
c_size_t left_high = j - num_to_swap_left;
if (low < left_high && left_high != (c_size_t)-1) {
c_QuickBentleyMcIlroyRecursive(array_base, low, left_high, size, cmp, args);
}
}
if (i + num_to_swap_right < high) {
c_QuickBentleyMcIlroyRecursive(array_base, i + num_to_swap_right, high, size, cmp, args);
}
}
/**
* @brief 工业级泛型自适应 Bentley-McIlroy 三路划分快速排序标准对外入口
*/
void c_QuickSort_BentleyMcIlroy(void* base, c_size_t num, c_size_t size, c_SortCompare_t cmp, void* args) {
if (!base || num < 2 || size == 0 || !cmp) {
return;
}
char* array_base = (char*)base;
c_QuickBentleyMcIlroyRecursive(array_base, 0, num - 1, size, cmp, args);
}
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
/**
* @brief 经典 Lomuto 划分函数(改自最简单快排,影子副本加固,安全防护)
*/
static c_size_t c_IterQS_Partition(char* array_base, c_size_t low, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) {
// 影子副本加固:完整镜像拷贝主轴,彻底粉碎泛型对调下的地址克隆别名污染
char pivot_buf[size];
memcpy(pivot_buf, array_base + (high * size), size);
c_size_t i = low;
for (c_size_t j = low; j < high; j++) {
if (cmp(array_base + (j * size), pivot_buf, args) < 0) {
c_QS_Swap(array_base + (i * size), array_base + (j * size), size);
i++;
}
}
c_QS_Swap(array_base + (i * size), array_base + (high * size), size);
return i;
}
/**
* @brief 工业级泛型非递归快速排序(显式模拟栈控制,彻底免疫 Stack Overflow
*/
void c_QuickSort_Iterative(void* base, c_size_t num, c_size_t size, c_SortCompare_t cmp, void* args) {
if (!base || num < 2 || size == 0 || !cmp) {
return;
}
char* array_base = (char*)base;
// 🌟 核心安全优化:对于 64 位系统,递归最大深度恒小于 64,开辟 128 长度的栈空间绝对可以闭环全球所有大数据
c_size_t stack[128];
long long top = -1; // 栈顶游标,使用有符号长整型防止自减溢出
// 将初始整轨区间的 [low, high] 闭区间边界压入显式模拟栈中
stack[++top] = 0;
stack[++top] = num - 1;
// 进入纯迭代控制状态机
while (top >= 0) {
// 出栈当前分治区间的右、左边界
c_size_t high = stack[top--];
c_size_t low = stack[top--];
// 1. 就地执行单路高抗性划分,锁定当前基准点的绝对无符号下标 pivot_idx
c_size_t pivot_idx = c_IterQS_Partition(array_base, low, high, size, cmp, args);
// 2. 模拟左分治管线:如果当前枢轴左侧还有可排空间
// 核心无符号防御:利用加法逆向控制 (low + 1 < pivot_idx) 代替传统减法,彻底切断下溢可能
bool has_left = (pivot_idx > 0 && low < pivot_idx - 1);
// 3. 模拟右分治管线:如果当前枢轴右侧还有可排空间
bool has_right = (pivot_idx < high);
// 🌟 工业级核心策略:优先将“大区间”压入栈顶,优先弹出来处理“小区间”!
// 这倒逼模拟栈的使用率呈对数律 $\mathcal{O}(\log N)$ 极限收敛,最大限度压缩运行时内存消耗
if (has_left && has_right) {
c_size_t left_len = (pivot_idx - 1) - low;
c_size_t right_len = high - (pivot_idx + 1);
if (left_len > right_len) {
// 左侧大,左侧优先压栈,右侧留着优先出栈处理
stack[++top] = low;
stack[++top] = pivot_idx - 1;
stack[++top] = pivot_idx + 1;
stack[++top] = high;
} else {
// 右侧大,右侧优先压栈
stack[++top] = pivot_idx + 1;
stack[++top] = high;
stack[++top] = low;
stack[++top] = pivot_idx - 1;
}
}
else if (has_left) {
stack[++top] = low;
stack[++top] = pivot_idx - 1;
}
else if (has_right) {
stack[++top] = pivot_idx + 1;
stack[++top] = high;
}
}
}