引言
大家好!欢迎继续关注我的排序算法系列。今天,我们要学习的是另一种非常基础且重要的排序算法——插入排序 (Insertion Sort)。
插入排序的思路非常贴近我们日常整理扑克牌的方式,理解起来相对自然。虽然它在最坏情况下的效率不高,但在某些特定场景下,它的表现甚至优于一些更高级的排序算法。
什么是插入排序?
想象一下你在玩扑克牌,手里已经握着几张排好序的牌(比如按点数从小到大)。现在你从牌堆里摸了一张新牌,你会怎么做?
通常,你会从右手边(或左手边)已排序的牌开始,逐张比较新牌和手里的牌,找到新牌应该插入的位置,然后将该位置及其后面的牌向后挪动一点,腾出空位,把新牌插进去。
插入排序就是基于这个思想:
- 将整个数组分为两部分: 左边是“已排序”区间,右边是“未排序”区间。
 - 初始状态: 已排序区间只包含数组的第一个元素 
arr[0]。 - 逐步扩展: 从未排序区间(从 
arr[1]开始)依次取出元素。 - 寻找位置并插入: 将取出的元素(我们称之为 
current或now)与已排序区间的元素从右向左逐一比较。 - 移动元素: 如果已排序区间的元素大于 
current,则将该元素向右移动一位。 - 重复比较和移动: 继续向左比较和移动,直到找到一个小于或等于 
current的元素,或者到达已排序区间的开头。 - 插入: 将 
current插入到最后移动元素的那个位置的后面(也就是空出来的位置)。 - 重复: 对未排序区间的所有元素重复步骤 3-7,直到所有元素都被插入到已排序区间中。
 
算法步骤详解 (以升序为例)
假设我们有数组 [5, 2, 4, 6, 1, 3]
- 初始: 
[5] | [2, 4, 6, 1, 3](|分隔已排序和未排序) - 处理 
2(now = 2):- 比较 
2和5->2 < 5-> 移动5->[_, 5] | [4, 6, 1, 3] j变为-1,循环结束。- 插入 
2到j+1(即 0) ->[2, 5] | [4, 6, 1, 3] 
 - 比较 
 - 处理 
4(now = 4):- 比较 
4和5->4 < 5-> 移动5->[2, _, 5] | [6, 1, 3] - 比较 
4和2->4 >= 2->break循环 (j为 0)。 - 插入 
4到j+1(即 1) ->[2, 4, 5] | [6, 1, 3] 
 - 比较 
 - 处理 
6(now = 6):- 比较 
6和5->6 >= 5->break循环 (j为 2)。 - 插入 
6到j+1(即 3) ->[2, 4, 5, 6] | [1, 3] 
 - 比较 
 - 处理 
1(now = 1):- 比较 
1和6->1 < 6-> 移动6->[2, 4, 5, _, 6] | [3] - 比较 
1和5->1 < 5-> 移动5->[2, 4, _, 5, 6] | [3] - 比较 
1和4->1 < 4-> 移动4->[2, _, 4, 5, 6] | [3] - 比较 
1和2->1 < 2-> 移动2->[_, 2, 4, 5, 6] | [3] j变为-1,循环结束。- 插入 
1到j+1(即 0) ->[1, 2, 4, 5, 6] | [3] 
 - 比较 
 - 处理 
3(now = 3):- 比较 
3和6->3 < 6-> 移动6->[1, 2, 4, 5, _, 6] - 比较 
3和5->3 < 5-> 移动5->[1, 2, 4, _, 5, 6] - 比较 
3和4 
 - 比较