#ifndef INCLUDED_C_BINARYINSERTIONSORT_H #define INCLUDED_C_BINARYINSERTIONSORT_H #ifndef INCLUDED_C_TYPES_H #include #endif /*INCLUDED_C_TYPES_H*/ #ifndef INCLUDED_C_MEMORY_H #include #endif /*INCLUDED_C_MEMORY_H*/ /* ------------------------------------------------------------------------------------------------------------------ */ /* */ /** * 通用折半插入排序函数 * @param base 指向待排序数组首元素的指针 * @param num 数组中元素的个数 * @param size 每个元素的大小(字节数) * @param compar 指向比较函数的指针 */ C_STATIC_FORCE_INLINE void c_BinaryInsertionSort(void* base, c_size_t num, c_size_t size, int (*compar)(const void*, const void*)) { char* arr = (char*)base; // 强转为 char* 以便按单字节进行指针偏移 // 分配一块临时内存,用于存放当前要插入的“哨兵”元素(temp) #define STACK_LIMIT 128 char stack_buf[STACK_LIMIT]; void* temp = NULL; if (size <= STACK_LIMIT) { temp = stack_buf; } else { temp = C_ALLOC(size); if (temp == NULL) return; } for (c_size_t i = 1; i < num; i++) { // temp = arr[i]:备份当前要插入的元素 memcpy(temp, arr + (i * size), size); // 1. 使用二分查找决定插入位置 [left, right] long long left = 0; long long right = i - 1; while (left <= right) { long long mid = left + (right - left) / 2; // 为了保证排序的稳定性(Stability), // 当 mid 元素等于 temp 时,应当继续向右区间查找,把 temp 放到相同元素的后面 if (compar(arr + (mid * size), temp) <= 0) { left = mid + 1; // 目标位置在右边 } else { right = mid - 1; // 目标位置在左边 } } // 循环结束时,left 就是元素应该插入的目标索引位置 // 2. 将 [left, i-1] 区间的元素全部向后移动一个位置 for (long long j = i - 1; j >= left; j--) { memcpy(arr + ((j + 1) * size), arr + (j * size), size); } // 3. 将 temp 插入到腾出来的 left 位置 memcpy(arr + (left * size), temp, size); } // Only trigger free if it was actually allocated from the heap if (size > STACK_LIMIT) { C_FREE(temp); } #undef STACK_LIMIT } #endif /*INCLUDED_C_BINARYINSERTIONSORT_H*/