常見排序算法(插入排序-曾經的筆記)

一、插入排序

1.直接插入排序

    思想:要將第i個記錄插入到已排好序的有序子列(由前i-1個元素組成)中,先順序查找到記錄的插入位置,然後進行插入操作,從而得到一個新的、記錄數增加1的有序表。插入位置的確定通過對有序子列中記錄按關鍵碼逐個比較得到的。

    遞歸版本:

    

    調用示例:

   

    模板參數 _It 是隨機(雙向)迭代器(比如,指向數組元素的普通指針類型) 參數 cmp 爲帶兩個參數的比較函數(或函數對象),遞增排序需要提供小於比較函數(比如,可提供標準庫中類型爲std::less<T> 的函數對象,需要包含頭文件#include<functional>),反之,則需要提供大於比較函數。

上述遞歸版本的思想是:當只有一個元素或爲空時,結束遞歸。當有多個元素時,考慮要從最後一個元素開始進行有序插入操作,但是之前的子列還未有序,故遞歸處理後,再實際對最後一個元素進行有序插入操作。

    非遞歸版本()

   

非遞歸版本:僅是對遞歸版本消除了遞歸操作。從後往前查詢插入位置,邊查詢邊進行移動操作。若從前往後查詢插入位置,則先查詢插入位置,然後進行移動操作。

【效率分析】

    空間效率:一個輔助單元。

    時間效率:向有序表的插入操作共進行了n-1趟,每趟操作分爲比較關鍵碼和移動記錄兩種操作,而比較的次數和移動記錄的次數取決於待排序列按關鍵碼的初始狀態。

    最好情況下:即待排序列已按關鍵碼有序,每趟操作只需1次比較。

                 總比較次數=n-1

                 總移動次數=0


    最壞情況下:即第j趟操作,插入記錄需要同前面有序序列的j個記錄進行j次關鍵碼比較,移動記錄的次數爲j+2次(額外的1次是複製第j+1個記錄備份引起的)。


    平均情況下:即第j趟操作,插入記錄時大約同前面的j/2個記錄進行關鍵碼比較,移動記錄的次數爲(j+2)/2次。


    由此,直接插入排序的時間複雜度爲O(n2)。是一個穩定的排序方法。

 

非遞歸版本()

 

2.折半插入排序

    思想:在一個有序表中進行查找和插入時,先確定待查記錄所在的範圍(區間),然後逐步縮小範圍直到找到或找不到該記錄的插入位置(折半查找插入位置),再進行插入操作。(僅僅是查找插入位置的方式與直接插入排序不同,故僅給出一個版本)

 

【時間效率】

log2(n+1)

    確定插入位置所進行的折半查找,關鍵碼的比較次數至多爲          ,次,移動記錄的次數和直接插入排序相同,故時間複雜度仍爲O(n2)。是一個穩定的排序方法。

 

3.希爾排序(縮小增量排序)

        思想:先將整個待排序的記錄序列分割成爲若干子序列分別進行直接插入排序,待整個序列中的記錄“基本有序”時,再對全體記錄進行一次直接插入排序。具體方法:

(1). 選擇一個步長序列t1t2,…,tk,其中ti>tjtk=1

    (2). 按步長序列個數k,對序列進行k趟排序;

(3). 每趟排序,根據對應的步長ti,將待排序列分割成若干長度爲m的子序列,分別對各子表進行直接插入排序。僅步長因子爲1時,整個序列作爲一個表來處理,表長度即爲整個序列的長度。

 

       【時效分析】

            希爾排序時效分析很難,關鍵碼的比較次數與記錄移動次數依賴於步長因子序列的選取,特定情況下可以準確估算出關鍵碼的比較次數和記錄的移動次數。目前還沒有人給出選取最好的步長因子序列的方法。步長因子序列可以有各種取法,有取奇數的,也有取質數的,但需要注意:步長因子中除1外沒有公因子,且最後一個步長因子必須爲1。希爾排序方法是一個不穩定的排序方法。

    下面的版本中的ShellInsert函數僅僅是在InsertSort2上增加了增量stride

 

有人在大量實驗的基礎上指出:

當增量序列爲delta(k)=2^t-k+1-1時,希爾排序時間複雜度爲O(n^1.5)

N在某個特定範圍內,希爾排序所用的比較次數和移動次數約爲N^1.3

n→∞,比較次數和移動次數可減少到n(logn)^2

 

4.其它插入排序 (如:2-路插入排序、表插入排序)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章