Swift算法-希爾排序Shell Sort

聲明:算法和數(shù)據(jù)結(jié)構(gòu)的文章均是作者從github上翻譯過(guò)來(lái),為方便大家閱讀。如果英語(yǔ)閱讀能力強(qiáng)的朋友,可以直接到swift算法俱樂(lè)部查看所有原文,以便快速學(xué)習(xí)。作者同時(shí)也在學(xué)習(xí)中,歡迎交流

希爾排序是基于插值排序的算法,通過(guò)將原始數(shù)據(jù)分為總數(shù)更小的幾個(gè)小數(shù)組,并在這些小數(shù)組中整理排序的方式來(lái)提升插值排序的性能。

這里有一個(gè)模仿希爾算法執(zhí)行過(guò)程的表演-匈牙利某大學(xué)傳統(tǒng)舞蹈小視屏

執(zhí)行原理

與插值排序通過(guò)對(duì)比相鄰的兩個(gè)元素的大小并在必要時(shí)候交換位置,希爾排序是通過(guò)比較相隔很遠(yuǎn)的兩個(gè)元素。

兩個(gè)元素之間的距離稱(chēng)為間隔。如果兩個(gè)元素在比較之后需要交換位置,則直接更換彼此的位置。這個(gè)過(guò)程減少了插值排序中很多不必要的中間復(fù)制過(guò)程,即從兩個(gè)元素更換位置前需要不斷交換相鄰元素的位置直到目的位置。
這里的最主要的思想就是,元素通過(guò)每次移動(dòng)較大間隔,整個(gè)數(shù)組可以快速形成局部排序好的情況。這個(gè)會(huì)讓接下來(lái)的交換變得更加快速。因?yàn)樵刂g不需要進(jìn)行過(guò)多次的位置交換。

一旦某一距離長(zhǎng)度的間隔比值交換完成,間隔會(huì)變得越來(lái)越小,然后進(jìn)行相應(yīng)間隔的比值交換,這樣的過(guò)程不斷重復(fù),直到間隔為1,也就是與插值排序同樣過(guò)程的情況。然而,在希爾排序中,由于大部分?jǐn)?shù)據(jù)在此時(shí)已經(jīng)整理完畢,所以最后間隔為1的比值交換速度非常快。

例子

假設(shè)我們要用希爾排序?qū)?shù)組[64, 20, 50, 33, 72, 10, 23, -1, 4]進(jìn)行整理。
我們從間隔為數(shù)組長(zhǎng)度二分一開(kāi)始:

n = floor(9/2) = 4

我們創(chuàng)建n個(gè)子數(shù)組。在每一個(gè)數(shù)組中,不同元素之間的間隔距離為n。在我們的例子中中,我們需要?jiǎng)?chuàng)建4個(gè)這樣的數(shù)組。這些數(shù)據(jù)會(huì)通過(guò)insertionSort()函數(shù)進(jìn)行整理排序。我們可以通過(guò)圖表進(jìn)行深入了解:

sublist 0:  [ 64, xx, xx, xx, 72, xx, xx, xx, 4  ]
sublist 1:  [ xx, 20, xx, xx, xx, 10, xx, xx, xx ]
sublist 2:  [ xx, xx, 50, xx, xx, xx, 23, xx, xx ]
sublist 3:  [ xx, xx, xx, 33, xx, xx, xx, -1, xx ]

如圖所示,每一個(gè)子數(shù)組里面只包含原數(shù)組中每一個(gè)第4個(gè)元素。其他非第4元素的用xx表示。所以第一個(gè)子數(shù)組為[64,72,4],第二個(gè)為[20,10],以此類(lèi)推。這里我們使用間隔的原因是我們不需要直接創(chuàng)建新的數(shù)組,所有的交換過(guò)程都在原始數(shù)組中完成。

現(xiàn)在我們開(kāi)始使用insertionSort()函數(shù)進(jìn)行每個(gè)子數(shù)組的整理排序。比如第一個(gè)子數(shù)組中,我們需要先將4和72交換位置,然后是4和64,然后72大于64不需要交換。整理后的第一個(gè)子數(shù)組為:
sublist 0: [ 4, xx, xx, xx, 64, xx, xx, xx, 72 ]
其他子數(shù)組也完成同樣過(guò)程,得到結(jié)果如下:

sublist 1:  [ xx, 10, xx, xx, xx, 20, xx, xx, xx ]
sublist 2:  [ xx, xx, 23, xx, xx, xx, 50, xx, xx ]
sublist 3:  [ xx, xx, xx, -1, xx, xx, xx, 33, xx ]

此時(shí),從原數(shù)組中看,結(jié)果是這樣的:
[ 4, 10, 23, -1, 64, 20, 50, 33, 72 ]
現(xiàn)階段并不是完全整理好的,但是對(duì)比最早時(shí)候的數(shù)據(jù),已經(jīng)相對(duì)有序的多。現(xiàn)在第一次比值交換結(jié)束,我們開(kāi)始進(jìn)行第二次交換。將第一次的交換間隔除以2,得到第二次間隔2.
n = floor(4/2) = 2
這也意味著我們這次只需要?jiǎng)?chuàng)建兩個(gè)子數(shù)組。

sublist 0:  [  4, xx, 23, xx, 64, xx, 50, xx, 72 ]
sublist 1:  [ xx, 10, xx, -1, xx, 20, xx, 33, xx ]

每個(gè)子數(shù)組包含間隔2的元素。重復(fù)之前的步驟,我們繼續(xù)使用insertionSort()函數(shù)進(jìn)行每個(gè)子數(shù)組的整理排序。結(jié)果如下:

sublist 0:  [  4, xx, 23, xx, 50, xx, 64, xx, 72 ]
sublist 1:  [ xx, -1, xx, 10, xx, 20, xx, 33, xx ]

通過(guò)觀察我們可以發(fā)現(xiàn),每一個(gè)子數(shù)組中均只有2個(gè)元素不在正確的位置上,所以在這一次的插值排序速度很快。

此時(shí)的原始數(shù)組為:
[ 4, -1, 23, 10, 50, 20, 64, 33, 72 ]
到這里第二次比值交換也結(jié)束,我們只需要進(jìn)行最后一次比值交換,間隔為1:
n = floor(2/2) = 1
這也意味著這次的子數(shù)組個(gè)數(shù)為1,可以直接對(duì)當(dāng)前的數(shù)組進(jìn)行整理,繼續(xù)使用insertionSort()函數(shù)。結(jié)果如下:
[ -1, 4, 10, 20, 23, 33, 50, 64, 72 ]
對(duì)希爾排序算法來(lái)說(shuō),大部分情況下它的性能是O(n^2),當(dāng)然運(yùn)氣好的時(shí)候是 O(n log n)。需要注意的是,希爾排序算法得到的是不穩(wěn)定序列,它可能會(huì)對(duì)數(shù)值相同的兩個(gè)元素進(jìn)行位置交換。

間隔序列

間隔序列決定了間隔的初始值以及每次迭代過(guò)程中新的間隔值。對(duì)于希爾排序算法來(lái)說(shuō),一個(gè)好的間隔序列可以讓整個(gè)算法表現(xiàn)的更好。

間隔序列的取值方法不是唯一的,在我們文中,我們采用的是整理數(shù)組個(gè)數(shù)的二分一,然后每次迭代繼續(xù)除以二分一的策略。

代碼

var arr = [64, 20, 50, 33, 72, 10, 23, -1, 4, 5]

public func shellSort(_ list: inout [Int]) {
    
    var sublistCount = list.count / 2
   
    while sublistCount > 0 {
        
        for index in 0..<list.count {
           
            guard index + sublistCount < list.count else { break }
            
            if list[index] > list[index + sublistCount] {
                swap(&list[index], &list[index + sublistCount])
            }
            
            guard sublistCount == 1 && index > 0 else { continue }
            
            if list[index - 1] > list[index] {
                swap(&list[index - 1], &list[index])
            }
        }
        sublistCount = sublistCount / 2
    }
}

shellSort(&arr)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,786評(píng)論 6 534
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,656評(píng)論 3 419
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,697評(píng)論 0 379
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,098評(píng)論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,855評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,254評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,322評(píng)論 3 442
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,473評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,014評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,833評(píng)論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,016評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,568評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,273評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,680評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,946評(píng)論 1 288
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,730評(píng)論 3 393
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,006評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • 排序的基本概念 在計(jì)算機(jī)程序開(kāi)發(fā)過(guò)程中,經(jīng)常需要一組數(shù)據(jù)元素(或記錄)按某個(gè)關(guān)鍵字進(jìn)行排序,排序完成的序列可用于快...
    Jack921閱讀 1,451評(píng)論 1 4
  • 該系列文章主要是記錄下自己暑假這段時(shí)間的學(xué)習(xí)筆記,暑期也在實(shí)習(xí),抽空學(xué)了很多,每個(gè)方面的知識(shí)我都會(huì)另起一篇博客去記...
    Yanci516閱讀 12,252評(píng)論 6 19
  • 排序算法說(shuō)明 (1)排序的定義:對(duì)一序列對(duì)象根據(jù)某個(gè)關(guān)鍵字進(jìn)行排序; 輸入:n個(gè)數(shù):a1,a2,a3,…,an輸出...
    BULL_DEBUG閱讀 792評(píng)論 0 3
  • 數(shù)據(jù)結(jié)構(gòu)與算法--排序之冒泡、選擇、插入、希爾 我們關(guān)注的主要對(duì)象是重新排列數(shù)組元素的算法,每個(gè)元素都有一個(gè)主鍵,...
    sunhaiyu閱讀 1,154評(píng)論 2 12
  • 用刷微博的時(shí)間來(lái)總結(jié)今日應(yīng)該有多好,每日精進(jìn)。 完成了Excel表格,計(jì)算機(jī)二級(jí)真的很惡心,沒(méi)有報(bào)班學(xué)習(xí)一頭霧水但...
    六夏妹兒閱讀 156評(píng)論 0 0