归并排序应使用索引传参而非切片以避免栈溢出;终止条件为 if left >= right: return,全程复用原数组,防止切片复制导致内存浪费和递归加深。

归并排序的递归结构怎么写才不栈溢出
递归终止条件没设对,或者切片操作没控制好边界,merge_sort 很容易在大数据量下触发 RecursionError: maximum recursion depth exceeded。Python 默认递归深度约 1000 层,而归并排序递归深度是 O(log n),表面看安全,但实际用 arr[left:right] 切片会复制子数组,既耗内存又隐式加深调用栈。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用索引传参代替切片:把
merge_sort(arr)改成merge_sort(arr, left, right),全程复用原数组 - 终止条件写成
if left >= right: return,不是if len(arr) —— 后者在切片版本里还行,索引版里必须靠下标判断 - 中点计算用
mid = left + (right - left) // 2,避免(left + right) // 2在极端大数时整型溢出(虽 Python int 不溢出,但习惯要养)
合并两个有序子数组的 while 循环怎么写才不漏元素
合并逻辑看似简单,但 while i 只处理了双方都未走完的情况,剩下没拷贝的尾巴常被忽略,导致结果缺数或顺序错乱。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 别用
extend或拼接,直接用下标往原数组填:合并目标是arr[left:right+1],所以每步写arr[k] = left[i]或arr[k] = right[j] - 主循环后必须补两段:
while i 和对应 right 的分支 - 如果嫌手动写两遍尾巴麻烦,可以统一用
left[i:] + right[j:]拼接再赋值——但仅限小数据,否则又回到切片开销问题
Python 里用 list.pop(0) 做合并会慢到离谱
有人图省事,在合并时写 if left[0] ,结果发现排序 10 万元素要好几秒——<code>list.pop(0) 是 O(n) 操作,整个合并退化成 O(n²)。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 永远用双指针(i/j 下标),不用
pop、pop(0)、insert或del - 如果真想避免下标管理,可预分配一个临时
result = [0] * (len(left) + len(right)),用单个k索引写入,比动态 list 更稳 - 注意:Python 的
sorted()和list.sort()是 Timsort,不是归并;别指望靠它反推归并写法
归并排序稳定吗?为什么交换位置后相等元素顺序可能变
归并排序本应是稳定排序,但实现时若合并条件写成 if left[i] ,遇到相等时会优先取 <code>right[j],破坏稳定性;正确做法是 且左优先。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 合并判断必须是
if left[i] ,且满足时取 <code>left[i]—— 这样左边相同值总比右边同值先落位 - 稳定性只在自定义对象排序时关键:比如按姓名排序学生列表,再按年龄归并,得保证同龄人姓名顺序不变
- 如果用
key参数包装对象,确保key返回可比较类型,否则会抛 <code>TypeError
真正卡住人的不是分治思想,而是合并时下标越界、尾巴遗漏、稳定性条件写反这三处——写完务必用 [3,1,4,1,5] 和 [2,7,1,8] 这类含重复、非幂次长度的输入手工走一遍合并过程。








