插入排序,顾名思义,就是把当前待排序的元素插入到一个已经排好序的列表里。犹如我们玩扑克牌的时候,将刚抽取的牌放入我们已经排好序的一滩中。
基本思想
把n个待排序的元素看成一个有序列表和一个无序列表,开始时有序表中只包含一个元素,无序表中包含n-1个元素,排序过程中,每次从无序表中取出第一个元素,将其与有序表中张元素进行比较,将它插入到有序表中适当的位置。
排序过程
以数组{47,50,38,79,83,32}为例。
第一趟:[47] 50,38,79,83,32
第二趟:[47,50] 38,79,83,32
第三趟:[38,47,50] 79,83,32
第四趟:[38,47,50,79] 83,32
第五趟:[38,47,50,79,83] 32
第六趟:[32,38,47,50,79,83]
最终结果:[32,38,47,50,79,83]
代码实现
原先都是使用Arrays类中一个static方法toString来打印数组,这次自己先准备一个打印数组的小方法。
//打印数组
static void printArray(int[] arr){
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
if(i<arr.length-1){
System.out.print(",");
}
}
System.out.print("]");
}
static void insertSort3(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 1; i < arr.length; i++) {
int insertValue = arr[i]; //待插入的数
int insertIndex = i; //可能要插入的索引
while (insertIndex > 0 && insertValue < arr[insertIndex - 1]) {
arr[insertIndex] = arr[insertIndex - 1];
insertIndex--;
}
arr[insertIndex] = insertValue;
}
}
或者:
// 插入排序
static void insertSort1(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 1; i < arr.length; i++) {
int insertValue = arr[i];
int insertIndex = i;
for (int j = i - 1; j >= 0; j--) {
if (arr[j] > insertValue) {
arr[j + 1] = arr[j];
insertIndex--;
} else {
break;
}
}
arr[insertIndex] = insertValue;
}
}
测试:
public static void main(String[] args) {
int[] arr = { 47, 50, 38, 79, 83, 32 };
insertSort3(arr);
printArray(arr);
}
结果:
[32,38,47,50,79,83]
算法分析
在最坏情况下,数组完全逆序,插入第2个元素时要考察前1个元素,插入第3个元素时,要考虑前2个元素,……,插入第N个元素,要考虑前 N - 1 个元素。因此,最坏情况下的比较次数是 1 + 2 + 3 + … + (N - 1),等差数列求和,结果为N(N-1)/2
,所以最坏情况下的复杂度为 O(N^2)
。
最好情况下,数组已经是有序的,每插入一个元素,只需要考查前一个元素,因此最好情况下,插入排序的时间复杂度为O(N)
。
再多说一点,
(1)选择排序是一种比较机械的排序,无论初始序列是怎么样的排序方式,选择排序都要经过N(N-1)/2
次比较。
(2)插入排序与原始序列的排序方式有关,最差的情况需要N(N-1)/2
次比较;最好的情况是需要N
次比较。
所以,在平均的情况下,插入排序要比选择排序快。
——————————————————————————————————————————————–如果有什么不对的地方,望批评指出。