一、插入排序
1.1 核心思想
将元素逐个插入到已排序序列的合适位置,就像整理扑克牌。
1.2 实现
public void insertionSort(int[] arr) { |
1.3 复杂度分析
| 情况 | 时间复杂度 | 说明 |
|---|---|---|
| 最好 | ( O(n) ) | 已排序,每次比较1次 |
| 最坏 | ( O(n^2) ) | 逆序 |
| 平均 | ( O(n^2) ) | |
| 空间 | ( O(1) ) | |
| 稳定性 | 稳定 |
1.4 部分有序的优势
插入排序对部分有序数组非常高效:
- 每个元素距离最终位置不远
- 实际比较和移动次数远小于 ( O(n^2) )
1.5 二分优化
查找插入位置时使用二分查找:
public void binaryInsertionSort(int[] arr) { |
比较次数降为 ( O(n \log n) ),但移动仍是 ( O(n^2) )。
二、希尔排序
2.1 核心思想
插入排序的改进版。先让相距较远的元素有序,再逐步缩小间隔,最终间隔为1时就是普通插入排序。
2.2 为什么有效
- 远距离交换让元素快速接近最终位置
- 最后一步插入排序时,数组已基本有序
2.3 实现
public void shellSort(int[] arr) { |
2.4 增量序列
不同增量序列影响复杂度:
| 增量序列 | 最坏复杂度 |
|---|---|
| ( n/2, n/4, … ) | ( O(n^2) ) |
| Hibbard: ( 2^k-1 ) | ( O(n^{3/2}) ) |
| Sedgewick | ( O(n^{4/3}) ) |
2.5 复杂度
| 情况 | 时间复杂度 |
|---|---|
| 最好 | ( O(n \log n) ) ~ ( O(n \log^2 n) ) |
| 最坏 | ( O(n^2) ) ~ ( O(n^{4/3}) ) |
| 平均 | 取决于增量序列 |
| 空间 | ( O(1) ) |
| 稳定性 | 不稳定 |
三、总结
| 特性 | 插入排序 | 希尔排序 |
|---|---|---|
| 最好时间 | ( O(n) ) | ( O(n \log n) ) |
| 最坏时间 | ( O(n^2) ) | ( O(n^2) ) ~ ( O(n^{4/3}) ) |
| 空间 | ( O(1) ) | ( O(1) ) |
| 稳定性 | 稳定 | 不稳定 |
| 适用 | 小数据、部分有序 | 中等数据 |
插入排序简单高效,尤其适合部分有序数据。希尔排序通过增量序列优化,是首个突破 ( O(n^2) ) 的排序算法,虽然不如快速排序常用,但在某些场景仍有价值。