插入排序就像整理扑克牌一样,逐个将新元素插入到已排序序列的正确位置,是一种直观且稳定的排序算法。下面这个表格能帮你快速抓住其要点和与其他简单排序算法的区别。
| 特性 | 描述 |
|---|---|
| 核心思想 | 将数组视为两部分(已排序+未排序),逐个将未排序元素插入已排序部分的正确位置 |
| 时间复杂度 | 最好情况 O(n)(数组已有序);最坏/平均情况 O(n²)(数组逆序/随机) |
| 空间复杂度 | O(1),是原地排序算法 |
| 稳定性 | 稳定排序算法(不改变相等元素的初始相对顺序) |
| 优势场景 | 小规模数据、基本有序的数据 |
🔄 算法步骤与示例
我们通过数组 [5, 2, 4, 6, 1, 3]的升序排序过程来理解插入排序:
-
初始状态:认为第一个元素
5自身是有序的。- 已排序部分:
[5];未排序部分:[2, 4, 6, 1, 3]
- 已排序部分:
-
第一轮插入 (i=1) :取出未排序部分第一个元素
2。- 与已排序部分的
5比较,2 < 5,将5后移。 - 将
2插入到位置0。结果:[2, 5, 4, 6, 1, 3]
- 与已排序部分的
-
第二轮插入 (i=2) :取出元素
4。- 与
5比较,4 < 5,5后移。 - 与
2比较,4 > 2,找到插入位置。 - 将
4插入到位置1。结果:[2, 4, 5, 6, 1, 3]
- 与
-
第三轮插入 (i=3) :取出
6。- 与
5比较,6 > 5,直接插入末尾。结果:[2, 4, 5, 6, 1, 3]
- 与
-
后续轮次:重复此过程,依次处理
1和3。- 最终结果:
[1, 2, 3, 4, 5, 6]
- 最终结果:
💻 Java代码实现
以下是插入排序的标准Java实现,它清晰地展示了“查找位置、移动元素、插入”的过程:
public class InsertionSort {
public static void insertionSort(int[] array) {
int n = array.length;
// 从第二个元素开始(下标1),因为第一个元素默认已排序
for (int i = 1; i < n; i++) {
int key = array[i]; // 当前待插入的元素
int j = i - 1; // 指向已排序部分的最后一个元素
// 在已排序部分中从后向前扫描,寻找key的插入位置并移动元素
while (j >= 0 && array[j] > key) {
array[j + 1] = array[j]; // 将大于key的元素向后移动一位
j--;
}
// 将key插入到找到的正确位置
array[j + 1] = key;
}
}
public static void main(String[] args) {
int[] arr = {5, 2, 4, 6, 1, 3};
System.out.println("排序前: " + java.util.Arrays.toString(arr));
insertionSort(arr);
System.out.println("排序后: " + java.util.Arrays.toString(arr));
}
}
⚖️ 对比其他简单排序
理解插入排序与冒泡排序、选择排序的差异,有助于你在不同场景下做出选择。
| 算法 | 平均时间复杂度 | 最好情况 | 最坏情况 | 稳定性 | 核心思想 |
|---|---|---|---|---|---|
| 插入排序 | O(n²) | O(n) (已有序) | O(n²) (完全逆序) | 稳定 | 将元素插入到已排序序列的正确位置 |
| 冒泡排序 | O(n²) | O(n) (已有序) | O(n²) (完全逆序) | 稳定 | 相邻元素比较交换,使最大/小值冒到顶端 |
| 选择排序 | O(n²) | O(n²) | O(n²) | 不稳定 | 每次选择最小/大元素放到已排序序列末尾 |
插入排序在实际应用中,尤其在处理小规模数据或部分有序数据时,往往比冒泡排序和选择排序更高效。
💎 核心要点与适用场景
- 核心要点:插入排序通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
- 主要优点:实现简单,对于小规模数据或基本有序的数据效率高,是稳定的原地排序算法。
- 主要缺点:对大规模乱序数据效率较低(O(n²)时间复杂度)。
- 适用场景:适用于数据量小(如n<50)、数据基本有序,或作为其他高级排序算法(如快速排序、归并排序)处理小子数组时的优化手段。