插入排序的實現與分析
阿新 • • 發佈:2018-11-05
讓你對一副雜亂無序的撲克牌進行排序,最常用的方法就是插入排序了。
插入排序的原理很簡單,在雜亂的牌中選出一張牌,然後把它插入到應有的位置,假設是從左到右依次遞減的。以鬥地主的規則為例,現在你手上的牌有{3, 2, J, K, A},那麼“2”就應該插在“3”前面,變成{2, 3, J, K, A},然後{2, J, 3, K, A} {2, K, J, 3, A} {2, A, K, J, 3}。
看個例子:
************************* 插入前:1 7 5 4 6 -3 8 待插入元素a[0]=1, 插入位置:0 插入後:1 7 5 4 6 -3 8 ************************* 插入前:1 7 5 4 6 -3 8 待插入元素a[1]=7, 插入位置:1 插入後:1 7 5 4 6 -3 8 ************************* 插入前:1 7 5 4 6 -3 8 待插入元素a[2]=5, 插入位置:1 插入後:1 5 7 4 6 -3 8 ************************* 插入前:1 5 7 4 6 -3 8 待插入元素a[3]=4, 插入位置:1 插入後:1 4 5 7 6 -3 8 ************************* 插入前:1 4 5 7 6 -3 8 待插入元素a[4]=6, 插入位置:3 插入後:1 4 5 6 7 -3 8 ************************* 插入前:1 4 5 6 7 -3 8 待插入元素a[5]=-3, 插入位置:0 插入後:-3 1 4 5 6 7 8 ************************* 插入前:-3 1 4 5 6 7 8 待插入元素a[6]=8, 插入位置:6 插入後:-3 1 4 5 6 7 8 *************************
附上程式碼:
public class insert_sort { public static void sort(int[] a){ int n=a.length; for (int i=0; i<n; i++){ for (int j=i; j>0&&(a[j-1]>a[j]); j--) swap(a, j-1, j);//for 2 }//for 1 } public static void swap(int a[], int i, int j){ int temp=a[i]; a[i]=a[j]; a[j]=temp; } public static void main(String[] args){ int[] a={1, 7, 5, 4, 6, -3, 8}; insert_sort.sort(a); } }
演算法分析:
假設陣列的長度為n,每次插入操作都要移動一些元素的位置,如果要把最後一個元素恰好最小,那麼就需要移動n-1個元素。這是最壞的情況,最好的情況依然是陣列一開始就是有序排列的。對於隨機排列的長度為N且不重複的陣列,平均情況下插入排序要~(N^2)/4次比較以及~(N^2)/4次交換。最壞情況下需要~(N^2)/次比較和~(N^2)/2次交換,最好情況下需要N-1次比較和0次交換。總的來說,插入排序的時間複雜度為O(N^2)。
驗證:
//C為比較次數,S為交換次數 public static void sort(int[] a){ int n=a.length; int C=0, S=0; int i, j, k; for (i=0; i<n; i++){ for (j=i; j>0&&(a[j-1]>a[j]); j--, C++, S++) swap(a, j-1, j);//for 2 }//for 1 System.out.println("C="+C+", S="+S); } ******************************************** 假設N=100 最壞情況: public static void main(String[] args){ int []a=new int[100]; for (int i=99; i>=0; i--) a[99-i]=i; insert_sort.sort(a); } 結果: C=4950, S=4950, (N^2)/2=5000 ******************************************** 最好情況: public static void main(String[] args){ int []a=new int[100]; for (int i=0; i<100; i++) a[i]=i; insert_sort.sort(a); } 結果: C=0(實際上比較了N-1次,因為沒有動作所以沒有記錄), S=0 ******************************************** 平均情況: public static void main(String[] args){ int []a=new int[100]; for (int i=0; i<100; i++) if (i%2==0) a[i]=i; else a[i]=-i; insert_sort.sort(a); } 結果: C=2500, S=2500, (N^2)/4=2500 ********************************************
通過測試可以看到,程式與理論吻合得相當好。還可以得出一個結論:插入排序需要的交換次數和陣列中倒置的數量相同,因為每次交換都改變了一組倒置的元素,當倒置的元素數量為0時就完成了排序。
實際上插入排序的效能優於選擇排序,但它和氣泡排序一樣,需要大量移動元素。你可以嘗試用連結串列來完成插入排序,那樣會免去移動元素的操作,但同時會付出更多空間的代價。
BY DXH924
2018.10.19