插入排序法及其改進
探討下插入排序法的傳統程式碼及改進程式碼
過程:宣告大小為100000的整型陣列arr和陣列help,Math.random()*10000000生成隨機數,將生成的隨機數同時賦值給陣列arr和help,arr使用兩種插入排序測試執行時間,而help使用Arrays.sort()排序,help用於對數器函式對數使用,在保證排序正確的前提下比較兩種插入排序的執行效率。
程式碼如下:
package 排序問題; import java.util.Arrays; public class 插入排序 { public static void main(String[] args) { int[] arr = new int[100000]; int[] help = new int[100000]; for(int i=0;i<100000;i++){ arr[i] = (int)(10000000*Math.random()); help[i] = arr[i]; } Arrays.sort(help); long startTime=System.currentTimeMillis(); //經典插入排序 for(int i=1;i<100000;i++) for(int j=i;j>0&&arr[j]<arr[j-1];j--){ int t = arr[j]; arr[j] = arr[j-1]; arr[j-1] = t; } /* //優化後的插入排序 for(int i=1;i<100000;i++) { int j = i; int e = arr[j]; while(j>=1&&e<arr[j-1]){ arr[j] = arr[j-1]; j--; } arr[j] = e; } */ long endTime=System.currentTimeMillis(); float excTime=(float)(endTime-startTime)/1000; System.out.println("run time is "+excTime+"s"); String s = compare(arr,help); System.out.println(s); } //對數器 private static String compare(int[] arr, int[] help) { for(int i=0;i<100000;i++) { if(arr[i]!=help[i]) { return "Sort is error"; } } return "Sort is ok"; } }
先介紹下傳統插入排序的思路:
先從第二個陣列元素開始遍歷到第n個數組元素(定義變數i從1增長到99999),對每個陣列元素進行迴圈操作:定義變數j=i,迴圈條件 j不是陣列第一個元素並且當前第j個元素小於第j-1個元素,交換兩個元素位置,j--;兩層for迴圈結束,即完成了排序。
測試一下傳統插入排序對含有100000個隨機數的陣列的排序時間:
可以看出排序時間是12.7秒,排序過程也是正確的。
再介紹下改進版的插入排序思路:
定義變數i從1增長到99999,對第i個數組元素進行如下操作:定義變數j=i,定義中間變數e儲存第j個元素的值,進行一個while迴圈,迴圈條件是 j>=1&&e<arr[j-1](當j是第二個元素及以後的元素時才有向前位移的意義,並且第i個元素的值小於第j-1個元素的值才能進行位移),迴圈內容是 將第j-1個元素的值賦值給第j個元素的值;執行完while迴圈後,當前第j-1個元素的值會大於等於第i個元素暫存在e的值,將第i個元素暫存值e賦值給第j個元素,即完成對第i個數在合適位置上的插入。對每個i進行完相應的操作時,即完成了對陣列的改良版插入排序。
接著測試一下改良版插入排序對含有100000個隨機數的陣列的排序時間:
執行時間是9.6秒,排序過程也是正確的。
分析:
案例:3421
(1)傳統插入排序進行排序過程:
對第二個元素4,判斷4是否小於第一個元素3,判斷結果是false,跳出迴圈
對第三個元素2,判斷2是否小於第二個元素4,判斷結果是true,交換2與4,得到:3241;判斷第二個元素2是否小於第一個元素3,判斷結果是true,交換2與3,得到:2341;由於2現在是第一個元素,所以跳出迴圈
對第四個元素1,判斷第四個元素1是否小於第三個元素4,判斷結果是true,交換4與1,得到:2314;判斷第三個元素1是否小於第二個元素3,判斷結果是true,交換1和3,得到:2134;判斷第二個元素1是否小於第一個元素2,判斷結果是true,交換2和1,得到:1234;由於1現在是第一個元素,所以跳出迴圈。
由於每一次交換需要進行三次操作,上述案例中,傳統插入排序進行了5次交換,即總共進行了15次操作。
(2)改良版插入排序進行排序過程:
對第二個元素4進行暫存操作,將4賦值給中間變數e,判斷e是否小於第一個元素3,判斷結果是false,跳出迴圈
對第三個元素2進行暫存操作,將2賦值給中間變數e,判斷e是否小於第二個元素4,判斷結果是true,將第二個元素4賦值給第三個元素,得到:3441;判斷e是否小於第一個元素3,判斷結果是true,將第一個元素3賦值給第二個元素,得到:3341;由於不存在第0個元素,所以跳出迴圈;將e賦值給第一個元素,得到:2341
對第四個元素1進行暫存操作,將1賦值給中間變數e,判斷e是否小於第三個元素4,判斷結果是true,將第三個元素4賦值給第四個元素,得到:2344;判斷e是否小於第二個元素3,判斷結果是true,將第二個元素3賦值給第三個元素,得到:2334;判斷e是否小於第一個元素2,判斷結果是true,將第一個元素2賦值給第二個元素,得到2234;由於不存在第0個元素,所以跳出迴圈;將e賦值給第二個元素,得到:1234
對第三個元素而言,先進行暫存操作,再進行兩次陣列元素賦值操作,最後將暫存值e賦值給第一個元素,一共進行了4次操作;相應的流程判斷,可知改良版排序一共進行了10次操作
總結:改良版插入排序可以簡化傳統插入排序中冗餘的交換操作,對陣列元素的依次位移減少了元素交換時賦值的操作次數,從而提升了排序的效率。