插入排序 - 整理扑克牌的算法
037插入排序:你手中的算法
📰 5W1H 发明者故事
Who(何人)- 发明者是谁?
发明者 :无单一发明者------插入排序是人类整理物品的自然直觉的算法化
背景:插入排序不像快速排序那样有明确的发明者和发明年份。它是人类直觉的形式化:当你抓一手扑克牌时,你会把每张新牌插入到已经排好序的牌中的正确位置。这个行为可能已经存在了数百年。最早的计算机程序员------包括艾达·洛夫莱斯(Ada Lovelace,1840年代)描述的算法中------就有类似的思想。
当时的处境:1950年代,当计算机开始处理商业数据时,排序成为了计算机科学中最重要的实际问题之一。IBM估计,1950年代计算机50%以上的时间都花在排序上。插入排序因其简单性成为了研究其他排序算法的基准。
When(何时)- 什么时候出现的?
时间 :1950年代(作为计算机算法被正式研究)
时代背景:
- IBM引入了专门的排序机(card sorter),处理穿孔卡片
- 商业数据处理(工资单、库存)需要大量排序
- 克努斯在TAOCP第三卷(1973)中对各种排序算法进行了系统分析
- "排序算法"成为计算机科学教学的核心内容
Where(何地)- 在哪里被研究?
地点 :IBM研究中心、贝尔实验室和各大学计算机系
环境:1950-60年代,排序算法研究是计算机科学中最热门的领域之一。每家大公司都有自己的排序程序,但没有人系统比较过它们。
What(何事)- 算法是什么?
算法 :插入排序(Insertion Sort)
核心思想 :将数组分为"已排序"和"未排序"两部分,每次从未排序部分取出第一个元素,将其插入到已排序部分的正确位置。
关键特性:
- 稳定排序:相等元素的相对顺序不改变
- 原地排序:只需O(1)额外空间
- 自适应性:对于接近有序的数组,效率极高(接近O(n))
- 在线算法:可以一边接收数据一边排序
Why(何因)- 什么时候用它?
优点:
- 小数组:n<20时往往比快速排序快(没有递归开销)
- 接近有序:每次只需少量移动
- 在线排序:数据实时到来时可以维护有序性
- 稳定性要求:需要保持相等元素相对顺序时
缺点:O(n²)平均时间复杂度,不适合大数组。
How(何果)- 如何实现?有什么影响?
算法步骤(对 [5,2,4,6,1,3] 排序):
[5|2,4,6,1,3] → 取2,插入:[2,5|4,6,1,3]
[2,5|4,6,1,3] → 取4,插入:[2,4,5|6,1,3]
[2,4,5|6,1,3] → 取6,不动:[2,4,5,6|1,3]
[2,4,5,6|1,3] → 取1,插入:[1,2,4,5,6|3]
[1,2,4,5,6|3] → 取3,插入:[1,2,3,4,5,6]
历史影响:
- 现代实现(如TimSort,Python/Java默认排序)在小数组上仍然使用插入排序
- 希尔排序(Shell Sort,1959)是插入排序的改进版,通过减少跨距来提速
- 快速排序的优化版本在小分区(n<10-20)时切换回插入排序
📝 自然语言需求定义
需求名称:实现插入排序,支持升序/降序,并统计比较和移动次数
功能需求
- 升序插入排序:对整数数组原地升序排序
- 降序插入排序:对整数数组原地降序排序
- 性能统计:统计排序过程中的比较次数和元素移动次数
验收标准
| 编号 | 测试场景 | 预期结果 | 验证方式 |
|---|---|---|---|
| 1 | 升序排序 [5,2,4,6,1,3] | [1,2,3,4,5,6] | 逐元素比较 |
| 2 | 降序排序 [5,2,4,6,1,3] | [6,5,4,3,2,1] | 逐元素比较 |
| 3 | 已排序数组(最好情况) | 不变,比较次数≈n-1 | 统计比较次数 |
| 4 | 逆序数组(最坏情况) | 正确排序,比较次数≈n²/2 | 统计比较次数 |
| 5 | 单元素数组 | 不变,无比较 | 边界条件 |
| 6 | 含重复元素 [3,1,2,1,3] | [1,1,2,3,3](稳定) | 相等元素相对顺序不变 |
💻 C语言实现文件
对应文件 : insertion_sort.c
编译运行:
bash
gcc -o insertion_sort_test insertion_sort.c
./insertion_sort_test