希爾排序(shell sort)是插入排序的一種。也稱縮小增量排序,是直接插入排序演算法的一種更高效的改進版本。希爾排序是非穩定排序演算法。該方法因dl.shell於2023年提出而得名。
既然是插入排序的改進版本,我們就先來看一看插入排序。
插入排序的原理就和打牌時我們抓牌一樣,每次摸到一張新的牌,我們都會將它插入到已經有序的牌序中,使之仍然有序。例如 我們 依次抽到4 2 9 j 10 8,那麼我們的牌序依次為4 , 2 4 , 2 4 9 , 2 4 9 j , 2 4 8 9 10 j,
抽到10為例,我們從後往前比較,10和j比較,10比j小, 所以j往後挪乙個位置,然後9和10比,10更大,說明找到了應在的位置,插入。對應的先來看一下插入排序的原始碼抽到最後的8 , 我們從後往前比較,8 < j ,j往後挪,8 < 10,10往後挪,8<9 ,9往後挪 ,8 >4,找到位置插入。
插入排序就是模擬了上述比較的過程。
可以看出,如果每次摸到一張新的牌,如果手中已有的最後一張牌比 剛摸得牌小,那麼就不用繼續比較了,這正好對應了插入排序的內層迴圈。
void insertion_sort(elemtype *a,int n)
}
我們知道插入排序的平均時間複雜度為o(n^2), 最佳時間複雜度為o(n),其效率的差異其實 就在內層迴圈①的執行次數上。可見如果初始序列有序或者說基本有序,那麼插入排序的效率就非常高了,最佳就是o(n)。但是插入排序每次只能交換相鄰的一對元素,也就是說每次只能消除乙個逆序對,而對於n個數,科學的研究表明:其逆序對的數目大致在 n(n-1) /4個,所以平均效率不可能超過o(n^2).
於是乎聰明的科學家們想到如果不交換相鄰的元素那? 而是去交換相隔比較遠的元素那?那麼我們每次交換消除的逆序對就不止乙個了!
希爾排序就是利用了這樣的性質。
希爾排序設定了乙個增量,每次通過縮小增量序列進行插入排序。
這個增量就是交換元素的間隔。
如上圖源**增量為5,也就是說5間隔的有 81 35 41 , 我們將這個子串行執行插入排序,變成 35 41 81 ,還有 94 17 75 變成了 17 75 94 , 11 95 15 變成了 11 15 96,
然後3間隔的進行排序,3間隔的排完序之後可以看出序列已經基本有序了,然後再將增量縮小為1,執行一次基本的插入排序,演算法完成。
void shellsort(elemtype *a,int n)
}}
對比插入排序,和希爾排序,可以看出希爾排序只是多了一層for迴圈,用來控制增量,而裡面兩層就是最基本的插入排序,只是將交換的位置 由 a[ j ] a [ j - 1 ] 變成了 a[ j ] a[ j - d ],增量的選取d就是當前的增量。
當然對增量的選取是十分重要的,上述**是希爾最初的增量分割,每次將增量縮小一半,也就是(增量序列:1,2,4,8,16...)但是當遇到下面這種情況,時間複雜度就o(n^2)了。顯然,對於增量的選取只要最後一次增量變為1,那麼一定可以使得序列有序。已知的最好增量序列是由sedgewick提出的(1, 5, 19, 41, 109,...),該序列的項來自
感興趣的同學自行實現或者問度娘吧。
希爾排序的簡單實現
希爾排序是插入排序的一種比較高階的變形。基本思路還是分治。顯然,對於乙個給定的順序表,如果順序表已經處於乙個 相對有序 的狀態時,插入排序進行的比較和移動次數都會有所減少。而對於較短的序列,常規的插入排序效率可以接受。因此可以考慮將序列分為幾個不同的子串行,分別進行插入排序後再合併。當順序表達到了一...
希爾排序實現
希爾排序算是插入排序的一種高階進化版,雖然希爾排序的實現比較簡單,但是它的原理證明非常複雜,由於能力有限,故沒有涉及。我直接上 吧。include intcontainer 1000001 int main void int increment,temp for increment n 2 incr...
C 實現簡單的希爾排序Shell Sort例項
include using namespace std void shellsort int iarray,int length i while isswap true 如果進行了交換說明 增量為jump的序列 可能存在不是有序的 程式設計客棧在檢測一遍 否則說明增量為jump的序列是有序的 int...