插入排序的主要思路是不斷地將待排序的數值插入到有序段中,使有序段逐漸擴大,直至全部的數值都進入有序段中。html
根據待排序的數值插入到有序段中的順序,能夠概括爲兩類:直接插入排序和折半查找插入排序。算法
直接插入排序的基本思想是依次將記錄序列中的每個記錄插入到有序段中,使有序段的長度不斷地擴大。數組
如今以一個實例簡單的說明一下這個算法的原理,假設數據存在數組a[]中,排序後的結果爲升序:數據結構
初始狀態: 45 37 61 87 66 23 29 45ide
45 37 61 87 66 23 29 45 ( 第一個元素認爲已經排好序) spa
第一次: 37 45 61 87 66 23 29 45 code
目標元素a[1] = 37, 比較 a[1]和a[0],因爲a[1] < a[0], 故須要交換位置。htm
第二次: 37 45 61 87 66 23 29 45 blog
目標元素a[2] = 61,爲了找到插入的位置須要分別比較a[0]和a[1]。分別比較a[2]和a[0]、a[1],a[1] < a[2],故不須要移動位置。排序
第三次: 37 45 61 87 66 23 29 45
目標元素a[3] = 87,爲了找到插入的位置須要分別比較a[0]、a[1]和a[2]。a[2] < a[3],故不須要移動位置。
第四次: 37 45 61 66 87 23 29 45
目標元素a[4] = 66,爲了找到插入的位置須要分別比較a[0]、a[1]、a[2]和a[3]。a[4] > a[2](61),a[4] < a[3](87),a[3]、a[4]交換位置。
第五次: 23 37 45 61 66 87 29 45
目標元素a[5] = 23,爲了找到插入的位置須要分別比較a[0]、a[1]、a[2]、a[3]和a[4]。a[5] < a[0](37),所以a[0]及後面已排好序的元素均須要後移,a[5]移至a[0]。
第六次: 23 29 37 45 61 66 87 45
目標元素a[6] = 29,爲了找到插入的位置須要分別比較a[0]、a[1]、a[2]、a[3]、a[4]和a[5]。a[6] > a[0](23),a[6] < a[1](37),所以a[1]及後面已排好序的元素均須要後移,a[6]移至a[1]。
第七次: 23 29 37 45 45 61 66 87
目標元素a[7] = 45,爲了找到插入的位置須要分別比較a[0]、a[1]、a[2]、a[3]、a[4]、a[5]和a[6]。a[7] >= a[3](45),a[7] < a[4](61),所以a[4]及後面已排好序的元素均須要後移,a[7]移至a[4]。
參考代碼:
1 #include <stdio.h> 2 3 #define MAX_NUM 80 4 5 void insertSort(int* a, int n) 6 { 7 int guard = -1; 8 for (int i = 0; i < n; i++) 9 { 10 guard = a[i]; 11 int j = i - 1; 12 while(guard < a[j] && j >= 0) 13 { 14 a[j+1] = a[j]; 15 j = j-1; 16 } 17 a[j+1] = guard; 18 19 for(int i = 0; i < n;i++) 20 { 21 printf("%d ",a[i]); 22 } 23 printf("\n"); 24 } 25 26 } 27 28 29 void binaryInsertSort(int* a, int n) 30 { 31 int guard = -1; 32 for (int i = 0; i < n; i++) 33 { 34 guard = a[i]; 35 int low = 0; 36 int high = i - 1; 37 38 while(low <= high) 39 { 40 int m = (low + high)/2; 41 if(guard < a[m] ) 42 high = m - 1; 43 else 44 low = m + 1; 45 46 } 47 48 for(int j = i-1; j>= high+1 ; --j) 49 a[j+1] = a[j]; 50 a[high+1] = guard; 51 52 for(int i = 0; i < n;i++) 53 { 54 printf("%d ",a[i]); 55 } 56 printf("\n"); 57 58 } 59 } 60 61 int main(int argc, char* argv[]) 62 { 63 int a[MAX_NUM]; 64 int n; 65 66 printf("Input total numbers: "); 67 scanf("%d",&n); 68 69 if( n > MAX_NUM ) n = MAX_NUM; 70 71 for(int i = 0; i < n;i++) 72 { 73 scanf("%d",&a[i]); 74 } 75 76 printf("排序步驟:\n"); 77 insertSort(a,n); 78 79 return 0; 80 }
案例結果截圖:
_
直接插入排序的時效性與穩定性分析:
(1)最好狀況:初始排序關鍵字已經有序,for循環進行一輪關鍵字比較,內循環while的條件均不知足,所以共比較n-1次,移動0次,算法時間複雜度爲O(n).
(2)最壞狀況:在待排序序列徹底逆序,for循環共運行n-1次,在while循環進行關鍵字比較,總的比較次數爲1+2+……+(n-1) = n(n-1)/2;
因爲在待排序序列所有逆序,古仔while循環進行關鍵字比較時,每次比較均知足循環條件,故須要移動i-1步,所以總共移動次數爲1+2+……+(n-1) = n(n-1)/2;
因此在最壞的狀況下,比較和移動次數均爲 n(n-1)/2次。
(3)平均狀況:在這種狀況下,外循環for循環的次數不變,可是內循環while循環在進行關鍵在比較時,平均有一半的元素在中間找到插入位置,比較次數比最壞狀況下降一半,同時移動元素次數也會下降一半,所以比較和移動次數均爲O(n(n+1)/2)/2,則時間複雜度爲O(n2)。
因爲直接插入排序是根據俄輸入序列的順序的大小來決定排序排序後的位置,是一種穩定的排序方法。
折半查找插入排序先取有序段的中間元素與查找值相比較。若是相等則查找成功;若是查找值大於中間元素,則再取高半部的中間元素與查找值相比較;若是查找值小於中間元素,則再取低半部的中間元素與查找值相比較。如此重複直到查找成功或最終爲找到該數爲止。在折半查找插入排序算法中,因爲進行關鍵字比較的次數比較少,因此算法的效率就比較高。它與直接插入排序惟一不一樣的就是在有序段中搜索插入位置是,使用折半查找方式,故算法的時間複雜度一樣爲O(n2),也是一種穩定的排序方法。
代碼在上述參考代碼中給出。
注:主要參考彭軍、向毅主編的 《數據結構與算法》