大家好!今天我们来聊聊一个简单却非常经典的排序算法------插入排序(Insertion Sort)。在所有的排序算法中,插入排序是最直观的一个。
一、插入排序的基本思想
插入排序的核心思想是:将一个待排序的元素,插入到已排好序的部分中,使得插入后的部分依然是有序的。
具体来说,插入排序会从数组的第二个元素开始,逐步与前面的元素进行比较,并将其插入到合适的位置,直到整个数组都排序完成。
举个例子:
- 假设我们有一个数组
[5, 3, 8, 4, 2]
,我们从第二个元素开始,逐个与前面的元素进行比较。 - 第一次比较,我们将
3
与5
比较,发现3
小于5
,就将3
插入到5
的前面,数组变成[3, 5, 8, 4, 2]
。 - 第二次比较,将
8
与前面的元素逐一比较,发现它已经大于5
,不需要移动。 - 继续这个过程,直到整个数组都变得有序。
二、插入排序的步骤
- 从第二个元素开始遍历,逐个元素插入到已排好序的部分。
- 对于每个元素,向前比较,直到找到合适的位置为止。
- 插入的操作可以通过移动元素的位置来完成,使得原来位置较大的元素腾出位置来插入新的元素。
三、插入排序的实现
我们通过 Java 来实现插入排序,看看这个过程是如何完成的。
java
public static void InsertSort(int[] arr) {
//i待插入数据下标
for (int i = 1; i < arr.length; i++) {
//j为已排序部分最后一个元素,即待排序元素的前一个元素,使j与j+1比较,j大交换,j小结束
for (int j = i - 1; j >= 0; j--) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
} else{
break;
}
}
}
}
四、插入排序的时间复杂度
插入排序的时间复杂度主要取决于待排序数据的顺序。
-
最优情况 :当数组已经是有序的时,内层循环不会执行任何移动操作,因此时间复杂度是 O(n) ,其中
n
是数组的长度。 -
最坏情况 :当数组是逆序时,每次插入都需要将元素移动到数组的前面,这时内层循环会执行
i
次移动操作。因此时间复杂度是 O(n²)。 -
平均情况 :假设元素是随机排列的,平均情况下,时间复杂度也为 O(n²)。
五、插入排序的优缺点
优点:
- 简单直观:插入排序的实现非常简单,而且非常适合小规模数据的排序。
- 稳定性:插入排序是稳定的排序算法,即相等的元素不会交换位置。
- 适用于部分有序的数组:当数组已经接近有序时,插入排序会表现得非常高效。
缺点:
- 时间复杂度高 :在数据规模较大的时候,插入排序的效率较低,特别是在最坏情况下,时间复杂度达到 O(n²)。
- 不适合大规模数据:对于大数据量的排序,插入排序不是最优选择。其他更高效的排序算法(如快速排序、归并排序)通常会更适用。
六、插入排序的应用场景
尽管插入排序在大规模数据中效率较低,但在一些特殊场景下,它依然非常有用:
- 小规模数据排序:在数据量较小的情况下,插入排序非常高效且简单。
- 部分有序的数组:如果数据已经部分有序,插入排序可以大大减少排序的工作量。
- 在线算法:插入排序是一种在线算法,也就是说它可以逐步地接收新的数据并进行排序。例如在实时排序数据流时,可以使用插入排序。