[轉] 插入排序

來源:互聯網
上載者:User

標籤: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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.