#include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /** * @brief 自顶向下归并排序核心合并内部函数(完全规避 c_size_t 下溢) * * 采用左闭右开区间映射,或精准的边界条件限制,确保所有的索引自加和自减都不触碰回绕风险。 */ static void c_MergeInternal(char* array_base, c_size_t low, c_size_t mid, c_size_t high, char* aux_buf, c_size_t size, c_SortCompare_t cmp, void* args) { // 将待合并的两个有序子区间 [low, mid] 和 [mid + 1, high] 的数据完整复制到辅助缓冲区 // 拷贝的总数据量为从 low 到 high(含)的闭区间元素总和 c_size_t total_elements = high - low + 1; memcpy(aux_buf + (low * size), array_base + (low * size), total_elements * size); c_size_t i = low; // 左半边子区间的游标起始点 c_size_t j = mid + 1; // 右半边子区间的游标起始点 // 双指针滑窗合并回原数组 for (c_size_t k = low; k <= high; k++) { if (i > mid) { // 左半边已经全部用尽,直接无脑拷贝右半边剩余元素 memcpy(array_base + (k * size), aux_buf + (j * size), size); j++; } else if (j > high) { // 右半边已经全部用尽,直接无脑拷贝左半边剩余元素 memcpy(array_base + (k * size), aux_buf + (i * size), size); i++; } else { // 核心双指针比对 char* elem_i = aux_buf + (i * size); char* elem_j = aux_buf + (j * size); // 使用 <= 0 判定。如果左边的值小于或等于右边,优先选用左边。 // 这正是归并排序能够完美保留相同元素原始先后相对位置(保持 Stable)的关键所在! if (cmp(elem_i, elem_j, args) <= 0) { memcpy(array_base + (k * size), elem_i, size); i++; } else { memcpy(array_base + (k * size), elem_j, size); j++; } } } } /** * @brief 递归驱动函数 */ static void c_MergeSortRecursive(char* array_base, c_size_t low, c_size_t high, char* aux_buf, c_size_t size, c_SortCompare_t cmp, void* args) { // 终止递归条件:当区间收缩到只包含 1 个元素时自然返回 if (low >= high) { return; } // 防整数溢出的中间索引计算法 c_size_t mid = low + ((high - low) >> 1); // 分治法阶段 1:左半区递归 c_MergeSortRecursive(array_base, low, mid, aux_buf, size, cmp, args); // 分治法阶段 2:右半区递归(由于 mid + 1 永远大于 mid,不可能在此处发生无符号数反向绕回) c_MergeSortRecursive(array_base, mid + 1, high, aux_buf, size, cmp, args); // 分治法阶段 3:就地执行双向有序序列的高效合并 c_MergeInternal(array_base, low, mid, high, aux_buf, size, cmp, args); } /** * @brief 工业级泛型自顶向下归并排序入口 * * @param base 指向待排序连续数组首元素的指针 * @param num 数组中元素的总个数 * @param size 每个元素所占用的内存字节大小 (sizeof) * @param cmp 带自定义上下文参数的比对回调函数指针 (不能为 NULL) * @param args 传递给比对回调函数的自定义上下文参数指针 */ void c_MergeSort(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; // 归并排序无法实现真正的泛型就地常数级存储,必须在堆或外部开辟一块大小为 N 的临时辅助阴影缓冲区。 // 这里采用标准 malloc 动态分配。如果在嵌入式环境中,可以将其修改为用户传入或静态内存池分配。 char* aux_buf = (char*)malloc(num * size); if (!aux_buf) { return; // 分配失败防御 } // 触发递归控制流:闭区间范围为 0 到 num - 1 // 由于 num >= 2,num - 1 经过了前置拦截,绝对不会引发 0 - 1 的无符号数最大值回绕灾难 c_MergeSortRecursive(array_base, 0, num - 1, aux_buf, size, cmp, args); // 严密清理辅助缓冲区,斩断内存泄漏 free(aux_buf); } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /** * @brief 内部辅助内联函数:获取两个无符号数中的较小值(防止宏重复计算) */ C_STATIC_FORCE_INLINE c_size_t c_InternalMin(c_size_t a, c_size_t b) { return (a < b) ? a : b; } /** * @brief 归并排序核心合并内部函数(复用双指针滑窗逻辑) */ C_STATIC_FORCE_INLINE void c_BU_MergeInternal(char* array_base, c_size_t low, c_size_t mid, c_size_t high, char* aux_buf, c_size_t size, c_SortCompare_t cmp, void* args){ c_size_t total_elements = high - low + 1; memcpy(aux_buf + (low * size), array_base + (low * size), total_elements * size); c_size_t i = low; c_size_t j = mid + 1; for (c_size_t k = low; k <= high; k++) { if (i > mid) { memcpy(array_base + (k * size), aux_buf + (j * size), size); j++; } else if (j > high) { memcpy(array_base + (k * size), aux_buf + (i * size), size); i++; } else { char* elem_i = aux_buf + (i * size); char* elem_j = aux_buf + (j * size); if (cmp(elem_i, elem_j, args) <= 0) { memcpy(array_base + (k * size), elem_i, size); i++; } else { memcpy(array_base + (k * size), elem_j, size); j++; } } } } /** * @brief 工业级泛型自底向上归并排序(纯迭代非递归,完全规避栈溢出风险) * * @param base 指向待排序连续数组首元素的指针 * @param num 数组中元素的总个数 * @param size 每个元素所占用的内存字节大小 (sizeof) * @param cmp 带自定义上下文参数的比对回调函数指针 (不能为 NULL) * @param args 传递给比对回调函数的自定义上下文参数指针 */ void c_MergeSort_BottomUp(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; // 分配 N 大小的临时阴影缓冲区 char* aux_buf = (char*)malloc(num * size); if (!aux_buf) { return; } // 外层循环:控制当前合并的子序列步长 sz (以 1, 2, 4, 8, ... 指数级翻倍递增) // 限制条件:sz < num,由于通过前置校验限制 num >= 2,因此循环至少执行一轮 for (c_size_t sz = 1; sz < num; sz = sz + sz) { // 内层循环:按当前子序列步长,成对进行两个子区间的有序合并 // 控制条件:low < num - sz。通过逆向加法或前置限制,确保 (num - sz) 不会发生无符号下溢 c_size_t limit = num - sz; for (c_size_t low = 0; low < limit; low += sz + sz) { // 计算当前左半边有序区间的终点 mid c_size_t mid = low + sz - 1; // 计算当前右半边有序区间的终点 high。 // 核心安全优化:若右半区不满足整步长大小,直接利用 c_InternalMin 将其安全截断到真实的最后一位 (num - 1) // 由于通过前置校验,num - 1 绝对不会产生无符号回绕 c_size_t high = c_InternalMin(low + sz + sz - 1, num - 1); // 就地执行数据合并 c_BU_MergeInternal(array_base, low, mid, high, aux_buf, size, cmp, args); } } // 清理堆空间 free(aux_buf); } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ // 设置小数组自适应截断阈值,通常在 12 - 16 之间性能达到极值 #define COMPONENT_MERGE_CUTOFF 15 /** * @brief 局部内联优化的泛型插入排序(供归并排序降级使用,规避下溢风险) */ C_STATIC_FORCE_INLINE void c_Internal_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 核心合并逻辑:直接从 src 合并到 dst,消除往返拷贝开销 */ C_STATIC_FORCE_INLINE void c_OptMergeInternal(char* src, char* dst, c_size_t low, c_size_t mid, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) { c_size_t i = low; c_size_t j = mid + 1; for (c_size_t k = low; k <= high; k++) { if (i > mid) { memcpy(dst + (k * size), src + (j * size), size); j++; } else if (j > high) { memcpy(dst + (k * size), src + (i * size), size); i++; } else { char* elem_i = src + (i * size); char* elem_j = src + (j * size); if (cmp(elem_i, elem_j, args) <= 0) { memcpy(dst + (k * size), elem_i, size); i++; } else { memcpy(dst + (k * size), elem_j, size); j++; } } } } /** * @brief 优化版交替控制流递归核心 * * 注意:这里的 src 和 dst 在每一层递归中都会发生调换,使得合并直接把数据推向正确的上一层载体。 */ static void c_OptMergeRecursive(char* src, char* dst, c_size_t low, c_size_t high, c_size_t size, c_SortCompare_t cmp, void* args) { // 优化点 1:小数组截断,当区间长度小于等于阈值时直接调用插入排序 if (high - low < COMPONENT_MERGE_CUTOFF) { c_Internal_InsertionSort(dst, low, high, size, cmp, args); return; } c_size_t mid = low + ((high - low) >> 1); // 优化点 3:通过互换 src 与 dst 指针角色,使得子层计算出来的有序序列直接存储在 src 中 c_OptMergeRecursive(dst, src, low, mid, size, cmp, args); c_OptMergeRecursive(dst, src, mid + 1, high, size, cmp, args); // 优化点 2:有序性前置检查。 // 如果左半区间的最大元素已经小于或等于右半区的最小元素,说明当前整体已经完全有序 // 此时只需直接从 src 拷贝到 dst,完全免去滑窗合并在指令和缓存上的无效消耗 char* left_max = src + (mid * size); char* right_min = src + ((mid + 1) * size); if (cmp(left_max, right_min, args) <= 0) { memcpy(dst + (low * size), src + (low * size), (high - low + 1) * size); return; } // 正常合并:将两个子序列安全推入 dst 目标 c_OptMergeInternal(src, dst, low, mid, high, size, cmp, args); } /** * @brief 工业级泛型优化版归并排序(哨兵阻断、小数组截断、零往返拷贝) */ void c_MergeSort_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; // 分配 N 大小的辅助阴影缓冲区 char* aux_buf = (char*)malloc(num * size); if (!aux_buf) { return; } // 初始化时将原始数据完整同步到辅助缓冲区中,以支持首次角色分调 memcpy(aux_buf, array_base, num * size); // 触发安全递归:此时传入的两个缓冲区分别为 aux_buf 和 array_base。 // 最终排好序的元素会完美收拢落回到原数组 array_base 中。 c_OptMergeRecursive(aux_buf, array_base, 0, num - 1, size, cmp, args); free(aux_buf); }