Files
cKit/Sort/c_BinaryInsertionSort.c
T

60 lines
2.6 KiB
C
Raw Normal View History

2026-08-30 22:24:45 +08:00
#include <c_BinaryInsertionSort.h>
void c_BinaryInsertionSort(void* base, c_size_t num, c_size_t size, c_SortCompare_t cmp, void* args) {
// 边界与防御性校验:元素少于 2 个或参数非法时无需排序
if (!base || num < 2 || size == 0 || !cmp) {
return;
}
char* array_base = (char*)base;
// 栈上开辟局部单元素缓冲区,用于暂存待插入的临时变量 v,规避 malloc 堆碎片
char v_buf[size];
// 外层循环:从第二个元素开始(无符号安全递增)
for (c_size_t i = 1; i < num; i++) {
const char* item_i = array_base + (i * size);
// 暂存当前需要插入的元素:v = a[i]
memcpy(v_buf, item_i, size);
// -----------------------------------------------------------------
// 核心:在已排好序的左侧区间 [0, i-1] 内执行二分查找,锁定 v 应该插入的绝对位置
// -----------------------------------------------------------------
c_size_t low = 0;
c_size_t high = i; // 右边界设为 i(开区间),这样 high 永远不会递减到负数
while (low < high) { // 注意:开区间控制条件为 low < high,而不是 <=
c_size_t mid = low + ((high - low) >> 1);
char* mid_elem = array_base + (mid * size);
// 执行您带 args 的自定义比对器
int cmp_res = cmp(v_buf, mid_elem, args);
if (cmp_res < 0) {
high = mid; // 目标值比 mid 小,直接收缩右开边界为 mid。彻底规避了 mid - 1 导致的下溢!
} else {
low = mid + 1; // 目标值 >= mid,向右半区逼近(保持稳定性)
}
}
// 此时 low == high,这个值就是新元素应该插入的精准无符号下标位置
c_size_t insert_pos = low;
// -----------------------------------------------------------------
// 数据搬运:将区间 [insert_pos, i-1] 内的元素统一单向往后平移一位
// 为确保绝对不发生 c_size_t 下溢,我们采用从后往前的减法前置拦截法
// -----------------------------------------------------------------
for (c_size_t j = i; j > insert_pos; j--) {
char* current = array_base + (j * size);
char* previous = array_base + ((j - 1) * size);
memcpy(current, previous, size); // a[j] = a[j-1]
}
// 将暂存的元素 v 写入最终空出来的安全插槽:a[insert_pos] = v
char* item_target = array_base + (insert_pos * size);
memcpy(item_target, v_buf, size);
}
}