插入排序 java实现
我们玩扑克纸牌时,需要对纸牌从左到右由小到大排序,我们通常是在一部分(可以是1张或者更多)已经有序的纸牌中,把其余纸牌一张一张插入,这个过程和插入排序一样。
以算法可视化网站为例:
插入排序:
{3,44,38,5,47,15,36,26,27,2,46,4,19,50,48}
把第一个元素(3)当作一个有序列表,然后把第二个元素(44)插入有序列表,44与3比较,44比3大,有序列表中的元素不需要移动,44直接放在元素3后面;
现在有序列表为{3,44}:要把38插入有序列表,38需要和44比较,38<44, 元素44后移一位,腾出给元素38的空间,38继续和3比较,38>3,元素3不动,38放置于3和44之间。
现在有序列表为{3,38, 44}:接下来的情况以此类推。
代码实现:
public static void main( String[] args ) {
int[] list = {3,44,38,5,47,15,36,26,27,2,46,4,19,50,48};
insertionSort(list);
for(int element:list)
System.out.printf("%d ",element);
}
public static void insertionSort(int[] list) {
for(int i=1; i<list.length; i++) {
int currentElement = list[i];
int j = 0;
for(j=i-1;j>=0 && list[j]>currentElement; j--) {
list[j+1] = list[j];
}
list[j+1] = currentElement;
}
}
对数组{3,44,38,5,47,15,36,26,27,2,46,4,19,50,48}排序后截图:
对于上述代码:
外层循环for(int i=1; i<list.length; i++)
i从1开始,默认把第一个元素(下标为0)当作一个有序列表,这里的i=1指从第二个元素开始遍历;
int currentElement = list[i];
获得当前要插入有序列表的元素;
for(j=i-1;j>=0 && list[j]>currentElement; j--) {
list[j+1] = list[j];
}
内层循环:j=i-1;将要插入有序列表的元素与有序列表中的元素一一比较(由右往左比较);
只要j没越界(为负数),并且有序列表中元素存在 > 我们要插入的元素,循环就会继续;
有序列表中大于我们要插入值得元素就会右移,给新元素腾出空间。
list[j+1] = currentElement;
新插入元素的位置,需要是j+1的位置,因为j–在最后一次内层循环后还会-1.
插入排序对部分有序的元素集合效率会更高:
- 元素集合中的元素离排序后的元素位置很近
- 在一个大的有序元素集合后继续添加一个小的元素集合
- 元素集合中只有几个元素位置不正确。
当问题规模为n时:
时间复杂度:
最差O(n^2):
元素集合完全逆序,比如{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}
比较次数:1+2+3+4+…+(n-1) = n(n-1)/2
移动次数:1+2+3+4+…+(n-1) = n(n-1)/2
最好O(n):
元素集合完全有序,比如{2 3 4 5 15 19 26 27 36 38 44 46 47 48 50 }
比较次数是n-1
移动次数是0