插入排序
插入排序也是一种比较简单的排序方法,想必大家都有玩过扑克牌。发牌过后,你拿起手牌展开,这个时候牌的顺序是杂乱无章的,插入排序的原理就类似于整理扑克牌的过程,将牌插入到合适的位置,最后你的手牌就会是从小到大(或者从大到小)的顺序了。
插入排序将待排数组分成两个区域,可以将左边看做有序区,右边看做无序区。当排序开始时,将无序区中最靠近有序区的元素取出,放入有序区的大小合适的位置。就这样每次都将最靠近有序区的元素无序区元素放入有序区的合适位置,知道无序区没有一个元素,排序就完成了。这个看上去可能有些抽象,下面举个例子就一目了然了。
(左边为有序区,右边为无序区,中间用 “|” 分隔开)
举例:
待排数组: 3,2,5,9,7,6,10
第一次排序: 3 | 2,5,9,7,6,10
第二次排序: 2,3 | 5,9,7,6,10
第三次排序: 2,3,5 | 9,7,6,10
第四次排序: 2,3,5,9 | 7,6,10
第五次排序: 2,3,5,7,9 | 6,10
第六次排序: 2,3,5,6,7,9 | 10
第七次排序:2,3,5,6,7,9,10 |
代码:
public void sort(int[] a) {
// TODO Auto-generated method stub
int N = a.length;
for(int i = 1; i < N; i++){
for(int j = i ; j>0 && less(a[j],a[j-1]); j--){
exchange(a, j, j-1);
}
}
}
(exchange函数为交换,less函数为比较大小)
关于时间复杂度
插入排序平均情况下大概需要N^2/4次比较和N^2/4次交换,最坏情况下(待排数组为逆序)大概需要N^2/2次比较和N^2/2次交换,最好情况下需要N-1次比较和0次交换。
所以插入排序的时间复杂度为O(n).
空间复杂度:
插入排序并未消耗太多的额外空间,所以空间复杂度为常数,S(1);总结:
从插入排序的原理上可以看出,插入排序对于部分有序的待排序列进行排序时比选择排序要快一些。举一个比较极端的例子,当待排序列为有序数组时,选择排序的时间复杂度任然为平方级别,O(n^2),而插入排序的运行时间则是线性级别的O(n).逆序的待排序列属于一种比较特殊的情况,一般还是比较少见,所以插入排序对于一些部分有序的待排序列的排序还是比较可观的。