插入排序算法 Java 附有程序范例
什么是插入排序算法?
插入排序是一种适用于小数据集的简单排序算法。在每次迭代中,算法:
- 从数组中删除一个元素。
- 将其与 排列.
- 将元素移动到正确的位置。
这种行为类似于玩家整理牌局的方式:每拿起一张新牌,都会将其向左推过所有较大的牌,直到到达正确的位置。由于所有移动操作都在原始数组内部进行,因此插入排序既是原地排序又是稳定的。
它属于同一类适合初学者的书籍。 Java 排序例程 气泡排序然而,对于已经部分有序的数据,它通常执行的写入操作要少得多。
插入排序算法过程
插入排序算法的工作流程如下:

动画重复了相同的三个步骤。 Java 以下程序将执行。试运行表 trac按照程序在运行时打印的方式,对示例数组 {860, 8, 200, 9} 执行这些步骤。
| 通过 | 关键要素 | 所做的比较 | 传递后的数组 |
|---|---|---|---|
| 1 | 8 | 8对860 | 8 860 200 9 |
| 2 | 200 | 200对860 | 8 200 860 9 |
| 3 | 9 | 9 对 860,然后 9 对 200 | 8 9 200 860 |
请注意,第三次遍历需要两次比较,因为键 9 必须经过两个更大的值。因此,比较次数会随着每个元素起始顺序的偏差而增加。
Java 使用插入排序算法对数组进行排序的程序示例:
以下程序对数组 {860, 8, 200, 9} 进行排序,并打印运行注释,因此每次比较和每次移位都清晰可见。将其保存为 InsertionSortExample.java 并使用 JDK 8 或更高版本进行编译。
package com.guru99; public class InsertionSortExample { public static void main(String a[]) { int[] myArray = {860,8,200,9}; System.out.println("Before Insertion Sort"); printArray(myArray); insertionSort(myArray);//sorting array using insertion sort System.out.println("After Insertion Sort"); printArray(myArray); } public static void insertionSort(int arr[]) { int n = arr.length; for (int i = 1; i < n; i++) { System.out.println("Sort Pass Number "+(i)); int key = arr[i]; int j = i-1; while ( (j > -1) && ( arr [j] > key ) ) { System.out.println("Comparing "+ key + " and " + arr [j]); arr [j+1] = arr [j]; j--; } arr[j+1] = key; System.out.println("Swapping Elements: New Array After Swap"); printArray(arr); } } static void printArray(int[] array){ for(int i=0; i < array.length; i++) { System.out.print(array[i] + " "); } System.out.println(); } }
运行该类会产生以下结果 trac此处所示。每个 排序通行号 行标记外层循环的一次迭代,每次交换后打印的行显示数组在该时刻的状态。
Code 输出:
Before Insertion Sort 860 8 200 9 Sort Pass Number 1 Comparing 8 and 860 Swapping Elements: New Array After Swap 8 860 200 9 Sort Pass Number 2 Comparing 200 and 860 Swapping Elements: New Array After Swap 8 200 860 9 Sort Pass Number 3 Comparing 9 and 860 Comparing 9 and 200 Swapping Elements: New Array After Swap 8 9 200 860 After Insertion Sort 8 9 200 860
插入排序的时间复杂度和空间复杂度
插入排序的性能很大程度上取决于输入数据的有序程度,这就是为什么最佳情况和最差情况相差一个数量级的原因。
| 案例 | 输入条件 | 时间复杂度 |
|---|---|---|
| 最棒的 | 数组已经排序,因此内部的 while 循环永远不会执行。 | O(N) |
| 一般 | 元素以随机顺序到达 | O(n²) |
| 最差 | 数组按逆序排列,因此每个键都会移动到数组的前面。 | O(n²) |
空间利用方式要简单得多。只有柜台。 i, j, n 和 key 创建数组时,数组会就地重新排列,因此无论输入增长到多大,辅助空间都是 O(1)。
由于内循环一旦遇到较小的值就会停止,因此插入排序被描述为自适应的:输入越接近有序顺序,运行时间就越接近线性。
插入排序的优点和缺点
尽管插入排序的常数因子很小,且其行为可预测,但它仍然在生产库中保留了下来,即使其平均时间为二次方。
优势
- 编写简单,易于操作 trac手工绘制,适合教学和面试。
- 稳定,因此共享同一键的记录将保持其原始相对顺序。
- 就地操作,除了输入数组之外,只需要 O(1) 额外的内存。
- 自适应,对于已经基本排序的数据,时间复杂度可达 O(n)。
- 在线,意味着它可以在新元素不断到达时对列表进行排序。
缺点
- 对于随机或逆序输入,二次时间复杂度使得它不适用于大型数组。
- 每次移位都会向数组写入数据,因此它移动的数据比选择排序要多。
- 当输入元素超过几十个时,归并排序和快速排序的性能就明显优于它。
一个实用的规则是,当数组较小、数据几乎有序,或者分治排序将一个分区减少到少数几个元素时,应该使用插入排序。
插入排序与 Bubble排序与选择排序
这三种算法都是二次比较排序,但它们在稳定性、对有序输入的反应以及执行的写入次数方面有所不同。
| 标准 | 插入排序 | Bubbl电子排序 | 选择排序 |
|---|---|---|---|
| 最好的情况 | O(N) | O(n) 时间复杂度,带有提前退出标志 | O(n²) |
| 平均情况和最坏情况 | O(n²) | O(n²) | O(n²) |
| 额外空间 | O(1) | O(1) | O(1) |
| 稳定 | 是 | 是 | 不,在标准数组版本中 |
| 自适应 | 是 | 是的,当使用标志优化时。 | 没有 |
| 写入数组 | 班次很多,但有序数据很少 | 多次交换 | 恰好 n-1 次交换 |
当写入操作成本很高时,选择排序胜出,因为它执行的交换操作最少。插入排序在几乎所有其他情况下都胜出,尤其是在处理部分有序数据时,这也是为什么像后面提到的那种库排序算法如此受欢迎的原因。 常见 Java 演习 JDK 内部机制会在分区非常小时切换到这种模式。
