前面的直接插入演算法,以抓牌為例,假設手氣比較好,抓牌的順序是從a直到k,那麼在這整個過程中都無需進行任何的插入動作,只需要將每次抓到的牌放在最後即可。假設現在手上已經抓到的牌的順序中逆序比較少,則抓牌的過程中插入操作就越少。因此,對於基本有序的序列排序,直接插入排序的效能是比較好的。這裡的基本有序是指較大的資料盡量在後面,而較小的資料盡量在前面。為了使得直接插入演算法更加有效,我們可以在最後使用插入演算法之前,使整個序列基本有序。
要使整個序列基本有序,我們採取的方法是採用跳躍分割的策略:將相距某個「增量」的元素組成乙個序列,然後不停地變換這個增量,這樣才能保證在子串行內分別進行排序得到的結果是基本有序而不是區域性有序。當然,對子序列進行排序的時候也可以使用直接插入排序演算法。以圖為例,假設增量為increment,當增量為1的時候,即相距為1的元素組成乙個序列,這表示子串行只有乙個,就是當前序列;當增量為2的時候,即相距為2的元素組成乙個序列,這表示子串行將有兩個;因此,當增量為increment的時候,子串行將有increment個。過程中,我們將increment不斷縮小直到1,對於每次的increment,我們將要對這increment個子序列分別進行排序。
這裡有幾點需要說明一下:途中同種顏色為指定增量下的子串行,可以看出子串行的個數為increment;另外,對於increment的初始值,我們設為元素個數對2取整(n/2)。因為假設增量大於一半了,那麼基本上每個子串行就只有乙個元素了。
我們將這個過程量化解釋一下:假設需要進行排序的序列個數個n,則將增量初始化為n/2,即increment = n/2,我們每次都需要式increment減1,從n/2直到1(最外層for迴圈);然後對於每個增量,裡面有increment個子序列,需要對這increment個子序列分別進行排序(第二個for迴圈)。
**如下:
void shellsort(int array, int arraycount)
{ int increment = arraycount/2; //增量
int subseqno; //
for(; increment > 0; --increment) //增量能取的個數
{ for(subseqno = 0; subseqno < increment; ++subseqno) //當增量為increment時,子串行的個數,用subseqno來做每個子串行首個元素下標
{ //接下來對每個子串行進行插入排序
for(int i = subseqno + increment; i < arraycount; i += increment)
{if(array[i] < array[i - increment]) //i處元素尋找插入位置
{int temp = array[i], j;
for(j = i - increment; j >= subseqno; j -= increment)
{if(array[j] > temp) //遇到比temp大的就後移一位
array[j + increment] = array[j];
else
break; //即當j出元素
可以看出希爾排序其實就是改進後的直接插入排序,它的每一步直接插入排序都將原序列趨於基本有序,因此,使得後面的插入排序更加方便。
經典排序演算法 希爾排序
注 本文參考 在講解希爾排序之前,我們有必要先回頭看一下插入排序的問題。插入排序不管陣列分布時怎麼樣的,都是一步步的對元素進行比較,移動,插入。比如 5,4,3,2,1,0 這種倒序序列,陣列末端的0要回到首位很費勁,比較和移動元素均需n 1次。這時就引出了希爾排序。希爾排序是希爾 donald s...
經典排序之希爾排序
希爾排序 基本思想 將待排序的序列分為若干組,在每組內進行直接插入排序,以使整個序列基本有序,然後再對整個序列進行直接插入排序。該方法實質上是一種分組插入方法。具體來說,先取乙個小於n的整數d1作為增量,把檔案的全部記錄分組。所有距離為d1的倍數的記錄放在同乙個組中。現在各組內進行直接插入排序 然後...
經典排序演算法 希爾排序Shell sort
經典排序演算法 希爾排序shell sort 希爾排序shell sort是基於插入排序 的一種改進,同樣分成兩部分,第一部分,希爾排序介紹 第二部分,如何選取關鍵字,選取關鍵字是希爾排序的關鍵 第一塊希爾排序介紹 準備待排陣列 6 2 4 1 5 9 首先需要選取關鍵字,例如關鍵是3和1 第一步分...