經(jīng)典四講貫通C++排序之二 希爾排序
我們都知道C++排序方法中,有四種常用方法插入排序、希爾排序、交換排序以及選擇排序。上一篇文章,我們介紹了插入排序,今天我們介紹另一種排序方法——希爾排序。(本系列文章統(tǒng)一 測(cè)試程序)
希爾排序
前面的算法的平均效率都不怎么好,但我們注意到直插排序在關(guān)鍵碼基本有序的情況下,效率是***的,并且,在關(guān)鍵碼的數(shù)量很少的時(shí)候,n和n2的差距也不是那么的明顯?;谝陨系氖聦?shí),D.L.Shell在1959年(老古董了)提出了縮小增量排序,基本思想是:取一個(gè)間隔(gap),將序列分成若干的子序列,對(duì)每個(gè)子序列進(jìn)行直插排序;然后逐漸縮小間隔,重復(fù)以上過(guò)程,直到間隔為1。在開始的時(shí)候,每個(gè)子序列里關(guān)鍵碼很少,直插的效率很高;隨著間隔的縮小,子序列的關(guān)鍵碼越來(lái)越多,但是在前面的排序基礎(chǔ)上,關(guān)鍵碼已經(jīng)基本有序,直插的效率依然很高。
希爾排序的時(shí)間復(fù)雜度不好估量,gap的選取也沒(méi)有定論,gap=[gap/2]的程序是***寫的,至于為什么,寫寫就知道了。
- template <class T>
- void ShellSort(T a[], int N, int& KCN, int& RMN)
- {
- KCN = 0; RMN = 0;
- for (int gap = N/2; gap; gap = gap/2)
- for (int i = gap; i < N; i++)
- {
- T temp = a[i]; RMN++;
- for (int j = i; j >= gap && ++KCN && temp < a[j - gap]; j -= gap)
- { a[j] = a[j - gap]; RMN++; }
- a[j] = temp; RMN++;
- }
- }
測(cè)試結(jié)果:
- Sort ascending N=10000 TimeSpared: 0ms
- KCN=120005 KCN/N=12.0005 KCN/N^2=0.00120005 KCN/NlogN=0.903128
- RMN=240010 RMN/N=24.001 RMN/N^2=0.0024001 RMN/NlogN=1.80626
- Sort randomness N=10000 TimeSpared: 10ms
- KCN=258935 KCN/N=25.8935 KCN/N^2=0.00258935 KCN/NlogN=1.94868
- RMN=383849 RMN/N=38.3849 RMN/N^2=0.00383849 RMN/NlogN=2.88875
- Sort descending N=10000 TimeSpared: 10ms
- KCN=172578 KCN/N=17.2578 KCN/N^2=0.00172578 KCN/NlogN=1.29878
- RMN=302570 RMN/N=30.257 RMN/N^2=0.0030257 RMN/NlogN=2.27707
注意到這時(shí)的測(cè)試結(jié)果很不準(zhǔn)確了,10000個(gè)整數(shù)的排序已經(jīng)測(cè)試不出什么來(lái)了(估計(jì)新機(jī)器都是0ms,我這里也有個(gè)別的時(shí)候全是0)。因此,下面用100000個(gè)整數(shù)的排序重新測(cè)試了一次:
- Sort ascending N=100000 TimeSpared: 140ms
- KCN=1500006 KCN/N=15.0001 KCN/N^2=0.000150001KCN/NlogN=0.903094
- RMN=3000012 RMN/N=30.0001 RMN/N^2=0.000300001RMN/NlogN=1.80619
- Sort randomness N=100000 TimeSpared: 230ms
- KCN=4041917 KCN/N=40.4192 KCN/N^2=0.000404192KCN/NlogN=2.43348
- RMN=5598883 RMN/N=55.9888 RMN/N^2=0.000559888RMN/NlogN=3.37086
- Sort descending N=100000 TimeSpared: 151ms
- KCN=2244585 KCN/N=22.4459 KCN/N^2=0.000224459KCN/NlogN=1.35137
- RMN=3844572 RMN/N=38.4457 RMN/N^2=0.000384457RMN/NlogN=2.31466
這個(gè)結(jié)果表明,希爾排序幾乎沒(méi)有最壞情況,無(wú)論是正序、逆序、亂序,所用時(shí)間都不是很多,附加儲(chǔ)存是O(1),的確非常不錯(cuò)。在沒(méi)搞清楚快速排序、堆排序之前,它的確是個(gè)很好的選擇,我當(dāng)年一直用它。
【編輯推薦】