標籤:style blog http color for re c html
一、直接插入排序演算法:
void insertSort(int* data, int len){ int sentry;//哨兵 int i,j; for(i = 1; i < len; i ++){//從第二個元素開始排序,前面的一個元素預設有序了 if (data[i] < data[i-1]){ sentry = data[i];//複製為哨兵 for(j = i-1; sentry < data[j]; j --){ data[j+1] = data[j];//記錄後移 } data[j+1] = sentry;//插入到適當的位置 } }}
直接插入排序的思想很簡單,每一趟排序有序表長度加1,在給記錄找出入位置的同時,後移比它大(這裡針對非遞減排序)的元素。分析直接插入排序演算法的時空複雜度。
空間上只需要一個哨兵做輔助空間,即空間複雜度為O(1);
對每一趟排序,需要完成比較和移動兩個操作,最好情況下,待排序的記錄已經有序,每一趟排序只需比較1次,共∑1 = (n-1)次比較,不需要移動元素;最壞情況下,待排序的記錄為逆序。比較次數共∑i = (n+2)(n-1)/2,移動共∑(i+1)=(n+4)(n-1)/2次。因此平均情況下,直接插入排序的時間複雜度為O(n^2)。
我選擇用這個中途上廁所回來清牌的例子,而不用抓牌的過程,因為我認為插入排序是一個原地排序,不需要申請額外的記錄表。抓牌的過程讓人感覺手裡的牌和還沒有抓上來的牌是不同的記錄表;而上廁所回來清牌,桌上亂序的牌就是一張待排序的記錄表,清牌的過程是在這個表上進行的,明顯沒有另闢空間。
二、折半插入排序
直接插入排序中,每次尋找插入位置時,都是依次往前進行比較。我們進行第i(i>1)趟排序時,前(i-1)個記錄已經有序,於是尋找插入位置我們可以用折半尋找。演算法如下:
1 void bInsertSort(int* data, int len){ 2 int sentry;//哨兵 3 int i,j; 4 int low,high,middle; 5 for(i = 1; i < len; i ++){ 6 sentry = data[i]; //複製哨兵 7 low = 0; 8 high = i - 1; 9 while(low <= high){ //尋找插入位置10 middle = (low + high) / 2; //折半下標11 if (sentry > data[middle]) //插入點在高半區12 low = middle + 1;13 else //插入點在低半區14 high = middle - 1;15 }16 for(j = i -1; j >= high + 1; j --){17 data[j+1] = data[j];//記錄後移18 }19 data[j+1] = sentry;//插入到適當的位置 20 }21 }
折半插入排序只是減少了尋找插入位置而進行的比較次數,而移動記錄的次數並沒有減少。因此折半插入的時間複雜度仍然是O(N^2)。
三、希爾排序
不論是直接插入排序還是折半插入排序,當待排記錄表很長時,排序效率會比較低,因為記錄表很長時,平均每趟移動的記錄數就會很多。
如,假設這個記錄表的長度是10005,當前面1000個記錄已經有序了,現在需要排第10001個記錄時,發現第10001個記錄需要插入到第一個位置,一共需要進行10000次移動元素。直接插入排序移動元素只能進行相鄰的局部移動,不能實現跨越式的移動。
希爾排序就是從這點出發對直接插入排序進行改進。它的基本思想是:先將整個待排序的記錄表分割成幾個子表,對子表分別進行直接插入排序,子表的長度比較小,排序的效率會比較高。演算法如下:
1 void shellInsert(int* data,int len, int dk){ 2 int sentry;//哨兵 3 int i,j; 4 for (i = dk ; i < len; i ++){ 5 if (data[i - dk] > data[i]){ 6 sentry = data[i]; 7 for(j = i - dk; j >= 0 && sentry < data[j]; j -= dk){ 8 data[j + dk] = data[j];//記錄後移 9 }10 data[j + dk] = sentry;//插入到適當的位置11 }12 13 }14 }15 16 void shellSort(int* data,int len, int dlta[],int dlen){17 int k;18 for(k = 0; k < dlen; k ++){ 19 shellInsert(data,len,dlta[k]); //一趟增量為dlta[k]的插入排序 20 }21 }
希爾排序中的子序列並不是簡單的逐段分割,而是將相隔某個增量的記錄組成一個子序列,的三趟排序的增量分別為5、3、1。
我們發現在希爾排序中,較小的記錄不是相鄰的局部移動,而是跳躍式的移動,在最後一趟時,增量為1,待排記錄表已經基本有序,利用直接插入排序即可完成排序,希爾排序的時間複雜度仍為O(n^2),但多項式係數比直接插入排序小,演算法效率較高。另外希爾排序不同與直接插入排序和折半插入排序,希爾排序是不穩定的排序演算法,可以考到中的兩個相同的記錄49在排序前後交換了順序,而直接插入排序和折半插入排序是穩定的,不會改變相同記錄之間的相對位置。
[轉載]
http://www.cnblogs.com/fengfenggirl/archive/2013/06/02/insertSort.html