简单排序 · 插入
插入排序 图解题解
这道题到底在问什么
把数组左边看作"已排序"。每次取右边第一个未排序的数,从右往左找到它该在的位置插入。
- 输入
- [5, 2, 4, 1, 3]
- 输出
- [1, 2, 3, 4, 5]
先想最直接的笨办法
为什么不像选择排序那样扫全局?因为左边已经有序了,新牌只要和左边从右往左挨个比,遇到第一个不比它大的就停——逆序时最慢要比到头(O(n²)),但近乎有序时几乎一比就停(O(n))。(动画第 3 步)
最优解:一步一步想明白
- 3为什么不像选择排序那样扫全局?因为左边已经有序了,新牌只要和左边从右往左挨个比,遇到第一个不比它大的就停——逆序时最慢要比到头(O(n²)),但近乎有序时几乎一比就停(O(n))。
- 4每插入完第 i 个数,前缀 0..i 一定有序。插入靠的是"把左边比它大的整体右移一格腾出空位",而不是交换——右移比交换省一次赋值,还保持稳定。
- 5i=1 cur=2先把第一个数 5 看作已排序区(绿色)。从下标 1 的 2 开始往左插。
- 6cur=2 j=0取出 cur=2 暂存(下标 1 这格视作空位)。和左边 5 比:5 大于 2,把 5 右移一格盖到下标 1,继续往左。
- 7j=-1 落 0j 已经越过最左端(j=-1),没有更多牌可比,把 cur=2 放进下标 0。前缀变成 [2,5] 有序。
- 8cur=4 j=1取出 cur=4。和左边 5 比:5 大于 4,5 右移到下标 2,j 退到下标 1。
- 9cur=4 j=1再和 2 比:2 不大于 4,循环停下——这就是关键负例分支,内层不再右移。把 cur=4 落到 2 右边那个空位。前缀 [2,4,5]。
- 10cur=1 j=2取出 cur=1。它比左边 5 小,5 右移到下标 3。
- 11cur=1 j=1继续往左:4 也大于 1,4 右移到下标 2。可见逆序时要连着右移好几格,这正是插入排序最坏 O(n²) 的来源。
- 12cur=1 j=-12 也大于 1,再右移;j 越过最左端,cur=1 落到下标 0。前缀 [1,2,4,5]。
- 13cur=3 落 2取出 cur=3:5 右移、4 右移,比到 2 时 2 不大于 3,停下,3 落进 2 和 4 之间。整个数组 [1,2,3,4,5] 有序。
- 16插入排序"自适应"——越接近有序越快,这是它相比选择排序的独特优势(选择排序无论如何都跑满 n²/2)。很多库的排序在小区间正是用它收尾。
⚠️ 容易写错的地方
✗ 错:while a[j] > cur:(漏了 j 越界判断)
✓ 对:while j >= 0 and a[j] > cur:
插到最前时 j 会一路减到 -1,先判 j >= 0 才不会数组越界;and 短路让越界判断在前
✗ 错:用边比边交换(三次赋值)
✓ 对:只右移、循环结束后落位一次
右移每步只一次赋值比交换省,且相等不动保证稳定
完整代码(Python)
Python
for i in range(1, len(nums)):
cur = nums[i] # 取出待插入的牌,腾出空位
j = i - 1 # 从前缀最右开始往左找
while j >= 0 and nums[j] > cur: # 比 cur 大的整体右移
nums[j + 1] = nums[j] # 右移一格(不是交换)
j -= 1
nums[j + 1] = cur # 遇到不比它大的,落位套路模板 · 插入排序(背下来)
for i in range(1, n):
cur, j = a[i], i - 1
while j >= 0 and a[j] > cur: # 大的右移腾位
a[j + 1] = a[j]; j -= 1
a[j + 1] = cur # 落位复杂度
时间复杂度
O(n²)
最坏(完全逆序)每个数都要移到头;近乎有序时退化到 O(n)
空间复杂度
O(1)
只在原数组上右移,不开额外数组
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 插入排序 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「插入」,换最直接的暴力解会差在哪?+
插入抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。