60 lines
2.6 KiB
C
60 lines
2.6 KiB
C
#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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|