你們好,我是阿濠,今篇內容跟你們分享的是排序算法之插入排序,很高興分享到segmentfault與你們一塊兒學習交流,初次見面請你們多多關照,一塊兒學習進步.
插入式排序屬於內部排序法
,是對於欲排序的元素
以插入的方式
找尋該元素的適當位置
,以達到排序
的目的。.算法
1.把n個待排序的元素
當作爲一個有序表和一個無序表
2.開始時有序表
中只包含一個元素
,無序表
中包含有n-1個元素
3.排序過程
中每次從無序表中取出第一個元素
,把它的排序元素依次與有序表元素進行比較
4.將它插入
到有序表中的適當位置
,使之成爲新的有序表
。segmentfault
由一羣牛,考試成績分別是: 100,34,119,1
使用插入排序法
將其排成一個從小到大的有序數列。
數組
步驟思路:
1.把n個待排序的元素
當作爲一個有序表和一個無序表
2.假設當前有序表
爲待排序的第一個元素
,每次從無序表中取出第一個元素
,把它的排序元素依次與有序表元素進行比較
3.將它插入
到有序表中的適當位置
,使之成爲新的有序表
。性能
//插入排序 public static void insertSort(int[] arr) { //使用逐步推導的方式來說解,便利理解 //第一輪{110,34,119,1}==>{34,101,119,1} //當前有序表包含一個元素爲110 //待插入數便是無序表:34,119,1 第一輪爲34 int interValue=arr[1];//arr[1]=34 int interIndex= 1 - 1;//即arr[1]前一個位置 //給insertVal找到插入的位置 //說明 //1. insertIndex >= 0保證在給insertVal找插入位置,不越界 //2. insertVal < arr[insertIndex] 待插入的數, 尚未找到插入位置 //3. 從小到大排序,則若34小於110,則須要讓位 while(interIndex >= 0 && interValue< arr[interIndex]){ arr[interIndex + 1]=arr[interIndex]; interIndex --; } //退出循環時,說明插入位置找到,insetIndex + 1 arr[interIndex +1 ] = interValue; System.out.println("第一輪排序結果:"); System.out.println(Arrays.toString(arr)); } 運行結果以下: 第一輪排序結果:[34, 110, 119, 1] //第二輪 interValue=arr[2]; interIndex=2 - 1; while(interIndex >= 0 && interValue< arr[interIndex]){ arr[interIndex + 1]=arr[interIndex]; interIndex --; } //退出循環時,說明插入位置找到,insetIndex + 1 arr[interIndex +1 ] = interValue; System.out.println("第二輪排序結果:"); System.out.println(Arrays.toString(arr)); 運行結果以下: 第一輪排序結果:[34, 110, 119, 1] 第二輪排序結果:[34, 110, 119, 1] //第三輪 interValue=arr[3]; interIndex=3 - 1; while(interIndex >= 0 && interValue< arr[interIndex]){ arr[interIndex + 1]=arr[interIndex]; interIndex --; } //退出循環時,說明插入位置找到,insetIndex + 1 arr[interIndex +1 ] = interValue; System.out.println("第三輪排序結果:"); System.out.println(Arrays.toString(arr)); 運行結果以下: 第一輪排序結果:[34, 110, 119, 1] 第二輪排序結果:[34, 110, 119, 1] 第三輪排序結果:[1, 34, 110, 119]
規律已經出來了,變化排序元素、比較交換
是類似
,改變的是從無序表中取出的元素
,即進行以下代碼抽整:學習
//使用for循環來把代碼進行簡化 for(int i = 1; i<arr.length;i++){ int interValue=arr[i]; int interIndex= i - 1; //給insertVal找到插入的位置 //說明 //1. insertIndex >= 0保證在給insertVal找插入位置,不越界 //2. insertVal < arr[insertIndex] 待插入的數, 尚未找到插入位置 //3. 從小到大排序,則若34小於110,則須要讓位 while(interIndex >= 0 && interValue< arr[interIndex]){ arr[interIndex + 1]=arr[interIndex]; interIndex --; } //退出循環時,說明插入位置找到,insetIndex + 1 if(interIndex+1 !=i){ arr[interIndex +1 ] = interValue; } System.out.println("第"+(i)+"輪排序結果:"); System.out.println(Arrays.toString(arr)); } //運行結果以下: 第1輪排序結果:[34, 110, 119, 1] 第2輪排序結果:[34, 110, 119, 1] 第3輪排序結果:[1, 34, 110, 119]
1.最好的狀況
,也就是要排序的表自己就是有序的
,此時只有數據比較
,沒有數據移動
,時間複雜度爲O(n)
。spa
2.最壞的狀況
,即待排序的表是逆序的狀況
,此時須要比較次數爲:2+3+…+n=(n+2)(n-1)/2 次
,而記錄移動的最大值也達到了(n+4)(n-1)/2次
. 3d
3.若是排序記錄是隨機的
,那麼根據機率相同的原則,平均比較和移動次數約爲 (n^2) / 4次
,所以,得出直接插入排序發的時間複雜度爲O(n^2)
。code
能夠看出一樣的是時間複雜度blog
直接插入排序法
比冒泡和簡單選擇排序
的性能要好一些
。排序
直接插入排序是穩定的
,不會改變相同元素的相對順序
。
二分(折半)插入
(Binary insert sort) 排序是一種在直接插入排序
算法上進行小改動
的排序算法
。其與直接排序算法最大的區別在於查找插入位置時使用的是二分查找的方式
,在速度上有必定提高。
步驟思路:
通常來講,插入排序都採用in-place在數組上實現
。
一、從第一個元素開始
,該元素能夠認爲已經被排序
二、取出下一個元素
,在已經排序的元素序列中
二分查找到第一個比它大的數的位置
三、將新元素插入到該位置後
四、重複上述兩步
假設插入數字:4
使用二分查找找到 mid
void BinInsertSort(int a[], int n) { int key, left, right, middle; for (int i=1; i<n; i++) { key = a[i];//當前認爲被排序的數 left = 0; right = i-1;//當前認爲被排序的數的右邊 //將開始和結束的下標進行比較,若是不一致則遍歷下一個 while (left<=right) { middle = (left+right)/2;//進行二分 //數組值比中間下標的數組值小,則在數組前一半中進行查找,即將end-1 if (a[middle]>key){ right = middle-1; } //若是而要計算的值比中間值大,則在數組後半段查找,即將start+1 else{ left = middle+1; } } for(int j=i-1; j>=left; j--) { a[j+1] = a[j]; } a[left] = key; } }
1.穩定
2.空間代價:O(1)
3.時間代價:插入每一個記錄須要O(log i)比較
,最多移動i+1次
,最少2次
。最佳狀況O(n log n),最差和平均狀況O(n^2)
。
二分插入排序
是一種穩定的排序。
當n較大時
,總排序碼比較次數比直接插入排序的最差狀況好得多
,但比最好狀況要差
,所元素初始序列已經按排序碼接近有序時,直接插入排序比二分插入排序比較次數少
。
二分插入排序元素移動次數與直接插入排序相同
,依賴於元素初始序列
。