归并排序性能瓶颈在于临时缓冲区管理,需预分配复用缓冲区、仅拷贝当前区间、避免跨区间无效拷贝。

归并排序的临时缓冲区损耗,主要来自重复分配、生命周期错配和缓存不友好这三类问题。真正影响性能的往往不是算法本身,而是数组变量怎么声明、何时分配、传给谁用。
避免每次合并都 malloc 一块新空间
传统写法在 merge 函数里直接 malloc(right - left + 1),看似简洁,实则每层递归都触发一次堆分配——8K 元素的数组可能产生上百次 malloc/free,碎片多、延迟高、还容易失败。
- 改用外部预分配:排序前一次性申请长度为
n的int*缓冲区,全程复用 - 把该指针作为参数传入所有递归调用,不新增局部变量
- 释放动作只在顶层函数结尾做一次,避免中间意外 return 导致泄漏
别让 temp 数组“跨区间”无效拷贝
很多实现会把整个原数组复制进 temp,再合并回原数组,但实际每次 merge 只处理 [left, right] 这一段。全量拷贝浪费带宽,尤其当数组很大而待合并段很小时更明显。
- 只复制当前区间:
for (int i = left; i - 合并时也严格控制写入范围,避免越界或冗余赋值
- 若使用静态全局缓冲区,注意多线程场景下需加锁或改用线程局部存储
用栈上数组替代小规模 malloc
对长度 ≤ 64 的子数组(比如递归到底层的几个元素),完全没必要走堆分配。现代编译器对固定大小的栈数组优化很好,且无管理开销。
- 在
merge函数开头判断区间长度,若 ≤ 64,直接声明int temp[64] - 超过则走预分配的堆缓冲区
- 这个阈值可调,一般 32–128 之间实测较优,取决于目标平台缓存行大小
合并逻辑中减少指针跳转与边界检查
临时数组不只是空间问题,访问方式也影响效率。频繁的 temp[i++] 和反复比较 i 会拖慢执行,尤其在嵌入式或低频 CPU 上。
- 用指针代替索引:
int *p1 = &arr[left], *p2 = &arr[mid+1], *pt = &temp[left]; - 合并循环内省略部分边界判断,靠末尾补全逻辑兜底(如先 while 两个指针都有效,再分别收尾)
- 确保
temp内存连续且对齐,有助于编译器向量化 load/store










