主要涉及的是内部排序
交换排序
冒泡排序
快速排序
选择排序
直接选择排序
堆排序
插入排序
=> 直接插入排序
希尔排序
归并排序
插入排序
1. 简介
插入排序(Insertion sort)是一种简单直观且稳定的排序算法。如果有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法——插入排序法,算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。本文介绍的是插入排序中的直接插入排序,下一篇将介绍插入排序中的希尔排序。
2. 算法原理
2. 1 算法的原理
插入排序的基本思想是:每步将一个待排序的记录,按其值的大小插入前面已经排序的数据中适当位置上,直到全部插入完为止。假设有一组无序序列 R0, R1, … , RN-1。
- 我们先将这个序列中下标为 0 的元素视为元素个数为 1 的有序序列。
- 然后,我们要依次把 R1, R2, … , RN-1 插入到这个有序序列中。所以,我们需要一个外部循环,从下标 1 扫描到 N-1 。
- 接下来描述插入过程。假设这是要将 Ri 插入到前面有序的序列中。由前面所述,我们可知,插入Ri时,前 i-1 个数肯定已经是有序了。所以我们需要将Ri 和R0 ~ Ri-1 进行比较,确定要插入的合适位置。这就需要一个内部循环,我们一般是从后往前比较,即从下标 i-1 开始向 0 进行扫描。
2. 2 算法示例
拿到原始数据,假设第一个元素已经是排好序的元素。
第一次循环i=1即将31和前面的数值比较找到合适的位置,显然需要和35交换位置;
第二次循环需要判断98在前面已经有序的数组中的位置,不需要交换;
如此循环n-1次,将每个元素都移动到正确的位置,完成排序。
2. 3 算法动画
3. 算法分析
3.1 复杂度
当数据正序时,执行效率最好,每次插入都不用移动前面的元素,时间复杂度为
O
(
N
)
O(N)
O(N)。 当数据反序时,执行效率最差,每次插入都要前面的元素后移,时间复杂度为
O
(
N
2
)
O(N^2)
O(N2)。所以,数据越接近正序,直接插入排序的算法性能越好。
由直接插入排序算法可知,我们在排序过程中,需要一个临时变量存储要插入的值,所以空间复杂度为
O
(
1
)
O(1)
O(1) 。
3.2 算法稳定性
直接插入排序的过程中,不需要改变相等数值元素的位置,所以它是稳定的算法。
时间复杂度(Min) | 时间复杂度(Avg) | 时间复杂度(Max) | 空间复杂度 | 稳定性 |
---|---|---|---|---|
O ( N ) O(N) O(N) | O ( N 2 ) O(N^2) O(N2) | O ( N 2 ) O(N^2) O(N2) | O ( 1 ) O(1) O(1) | 稳定 |
4. 算法实现
public static void insertSort(int arr[]) {
int length = arr.length, tmp, j;
for (int i = 1; i < length; i++) {// 假设第一个已经有序顾从1开始
tmp = arr[i];// 记录当前需要排序的值
j = i - 1;
// 当前位置往前找,如果小于当前值,则将该位置的值往后移动一位
for (; j >= 0 && arr[j] > tmp; j--) {
arr[j + 1] = arr[j];
}
if (j < i - 1) {// 如果有移动,则将当前排序值放到正确的位置
arr[j + 1] = tmp;
}
}
}