一,插入排序介紹
插入排序是基於比較的排序。所謂的基於比較,就是通過比較數組中的元素,看誰大誰小,根據結果來調整元素的位置。
因此,對於這類排序,就有兩種基本的操作:①比較操作; ②交換操作
其中,對於交換操作,可以優化成移動操作,即不直接進行兩個元素的交換,還是用一個樞軸元素(tmp)將當前元素先保存起來,然后執行移動操作,待確定了最終位置后,再將當前元素放入合適的位置。(下面的插入排序就用到了這個技巧)--因為,交換操作需要三次賦值,而移動操作只需要一次賦值!
有些排序算法,比較次數比較多,而移動次數比較少,而有些則相反。比如,歸並排序和快速排序,前者移動次數比較多,而后者比較次數比較多。
這里主要介紹插入排序
二,插入排序算法分析
插入排序算法有種遞歸的思想在里面,它由N-1趟排序組成。初始時,只考慮數組下標0處的元素,只有一個元素,顯然是有序的。
然后第一趟 對下標 1 處的元素進行排序,保證數組[0,1]上的元素有序;
第二趟 對下標 2 處的元素進行排序,保證數組[0,2]上的元素有序;
.....
.....
第N-1趟對下標 N-1 處的元素進行排序,保證數組[0,N-1]上的元素有序,也就是整個數組有序了。
它的遞歸思想就體現在:當對位置 i 處的元素進行排序時,[0,i-1]上的元素一定是已經有序的了。
三,插入排序算法實現
1 public class InsertSort{ 2 3 public static <T extends Comparable<? super T>> void insertSort(T[] a){ 4 for(int p = 1; p < a.length; p++) 5 { 6 T tmp = a[p];//保存當前位置p的元素,其中[0,p-1]已經有序 7 int j; 8 for(j = p; j > 0 && tmp.compareTo(a[j-1]) < 0; j--) 9 { 10 a[j] = a[j-1];//后移一位 11 } 12 a[j] = tmp;//插入到合適的位置 13 } 14 } 15 16 //for test purpose 17 public static void main(String[] args) { 18 Integer[] arr = {34,8,64,51,32,21}; 19 insertSort(arr); 20 for (Integer i : arr) { 21 System.out.print(i + " "); 22 } 23 } 24 }
四,復雜度分析
①插入排序的時間復雜度 就是判斷比較次數有多少,而比較次數與 待排數組的初始順序有關,當待排數組有序時,沒有移動操作(第8行for不成立),此時復雜度為O(N),當待排數組是逆序時,比較次數達到最大--對於下標 i 處的元素,需要比較 i-1 次。總的比較次數:1+2+...+N-1 ,故時間復雜度為O(N^2)
①可以看出,算法中只用到了一個臨時變量(第6行),故空間復雜度為O(1)
其實,插入排序的比較次數與數組的逆序數相關,因為插入排序在將某個元素插入到合適位置時(代碼第12行),其實就是消除這個元素的逆序數。
由定理:N個互異數的數組的平均逆序數是 N(N-1)/4,可知:基於相鄰元素之間的比較和交換的算法的時間復雜度的一個下界為O(N^2)
比較冒泡排序啊。。。。它采用的思路是:相鄰兩個元素比較,將小的放在前頭。故冒泡排序的時間復雜度為O(N^2)。。。
基於上面這個定理,另外一個排序算法:希爾排序,采用了增量序列。因此,它可能獲得一個更好的時間復雜度。
比如,當希爾排序使用Hibbard增量序列時,它的最壞運行時間為O(N3/2)
五,參考資料
《數據結構與算法分析》MAW著