[数据结构·排序] 插入排序及其变种
这是一份关于插入排序及其变种的详细讲解。我为您整理了三种主要的插入排序算法:直接插入排序、折半插入排序和希尔排序。
插入排序算法详解
插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
本文将详细介绍三种主要的插入排序方式:
- 直接插入排序 (Direct Insertion Sort)
- 折半插入排序 (Binary Insertion Sort)
- 希尔排序 (Shell Sort)
1. 直接插入排序 (Direct Insertion Sort)
这是最基础的插入排序。它的核心思想是将数组分为“已排序区间”和“未排序区间”。初始时,已排序区间只有一个元素。
算法流程
- 从第一个元素开始,该元素可以认为已经被排序。
- 取出下一个元素(称为“基准”或
key),在已经排序的元素序列中从后向前扫描。 - 如果该元素(已排序)大于新元素,将该元素移到下一位置。
- 重复步骤 3,直到找到已排序的元素小于或者等于新元素的位置。
- 将新元素插入到该位置后。
- 重复步骤 2~5。
适用情况
- 数据量较小:对于少量元素(如 $n \le 50$),其简单性使得开销很小,甚至优于复杂的排序算法(如快速排序)。
- 基本有序:如果数组已经“几乎”是有序的,直接插入排序的效率极高,接近 $O(n)$。
- 需要稳定排序:它不会改变相同元素原本的相对顺序。
缺点
- 大数据量效率低:平均时间复杂度为 $O(n^2)$。如果有 10000 个数据且完全逆序,效率会非常差。
- 移动次数多:每次插入都需要移动大量元素。
C++ 代码实现
1 |
|
3. 希尔排序 (Shell Sort)
希尔排序(也称缩小增量排序)是插入排序的一种更高效的改进版本。它打破了时间复杂度 $O(n^2)$ 的限制。
算法流程
分组:将待排序的数组元素按下标的一定增量(gap)分组。
组内排序:对每组使用直接插入排序算法排序。
缩小增量:随着增量逐渐减少,每组包含的关键词越来越多。
最终排序:当增量减至 1 时,整个文件恰被分成一组,算法终止。
常用的增量序列是 gap = gap / 2(希尔建议),但也有更高效的序列如 Knuth 序列。
适用情况
中等规模数据:在几千到几万规模的数据上表现良好,通常快于 $O(n^2)$ 的算法。
不需要稳定性:当不关心相同元素的相对顺序时。
内存受限:它是一种原地排序算法,不需要大量的额外空间。
缺点
不稳定:这是希尔排序与前两种最大的区别。由于多次跳跃式移动,相同元素的相对位置可能会改变。
增量序列选择复杂:不同的增量序列(Gap Sequence)会显著影响性能。
最坏情况仍较差:虽然平均情况不错,但使用某些增量序列的最坏情况仍接近 $O(n^2)$。
C++ 代码实现
C++
1 |
|
总结对比
| 算法名称 | 平均时间复杂度 | 最好情况 | 最坏情况 | 空间复杂度 | 稳定性 | 核心特点 |
|---|---|---|---|---|---|---|
| 直接插入排序 | $O(n^2)$ | $O(n)$ | $O(n^2)$ | $O(1)$ | 稳定 | 简单,适合小数据或基本有序数据 |
| 折半插入排序 | $O(n^2)$ | $O(n)$ | $O(n^2)$ | $O(1)$ | 稳定 | 减少了比较次数,但没减少移动次数 |
| 希尔排序 | $O(n^{1.3})$ (依赖增量) | $O(n)$ | $O(n^2)$ | $O(1)$ | 不稳定 | 通过预处理(大幅度移动)打破了线性限制 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Welcome To My-Blog!
评论
