1. 程式人生 > >插入排序法及其改進

插入排序法及其改進

探討下插入排序法的傳統程式碼及改進程式碼

過程:宣告大小為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次操作


總結:改良版插入排序可以簡化傳統插入排序中冗餘的交換操作,對陣列元素的依次位移減少了元素交換時賦值的操作次數,從而提升了排序的效率。