通過(guò)算法了解Swift 3——“選擇排序”

沒(méi)有什么比數(shù)據(jù)結(jié)構(gòu)和算法能更純粹的展示一門(mén)編程語(yǔ)言的用法了疾嗅。做為更具表現(xiàn)力黍衙、更加類型安全、支持多種編程范式的Swift 3料扰,單純理解語(yǔ)法上的變化是遠(yuǎn)遠(yuǎn)不夠的凭豪,讓我們通過(guò)一系列算法,從設(shè)計(jì)初衷到具體的語(yǔ)言實(shí)現(xiàn)晒杈,來(lái)感受這些Swift proposal吧嫂伞。有些改變的確帶了breaking change,但是拯钻,接受它們帖努,你一定可以收獲更多。

源自泊學(xué)

選擇排序(Selection sort)

SelectionSort

Selection sort是一種和insertion sort類似的排序方法粪般,它同樣只適用于對(duì)規(guī)模不大的集合進(jìn)行排序拼余。
它的核心思想是,在序列內(nèi)部亩歹,把序列邏輯上分成已排序和未排序兩部分匙监,不斷找到未排序部分中最符合排序規(guī)則的元素,添加進(jìn)已排序部分小作,直到序列中所有元素都已經(jīng)添加到了已排序部分亭姥,此時(shí),整個(gè)序列就排序完成了躲惰。
我們用數(shù)組[1, 5, 7, 6]進(jìn)行降序排列來(lái)舉例致份,整個(gè)過(guò)程是這樣的:
1、我們用一個(gè)豎線來(lái)區(qū)分序列中“已排序”和“未排序”的部分础拨,初始時(shí)氮块,“已排序“部分為空,”未排序“部分是整個(gè)序列诡宗;

[ | 1, 5, 7, 6 ]

然后滔蝉,第一個(gè)應(yīng)該從“未排序部分”取出的元素,是7塔沃。把7和緊挨豎線右側(cè)的數(shù)字交換蝠引,并且把豎線向右移動(dòng)一個(gè)位置;

[ | 1, 5, 7, 6 ] 
    *<--->*
 [ | 7, 5, 1, 6 ]
   ^-->
[ 7, | 5, 1, 6 ]

然后蛀柴,繼續(xù)從“未排序部分”取出元素6螃概,它和5交換,并且把豎線移動(dòng)一個(gè)位置:

[ 7, | 5, 1, 6 ]
       *<--->*
[ 7, | 6, 1, 5 ]
     ^-->
[ 7, 6, | 1, 5 ]

接下來(lái)是5鸽疾,交換它和1的位置吊洼,然后把豎線向右移動(dòng)一個(gè)位置:

[ 7, 6, | 1, 5 ]
          *  *
[ 7, 6, | 5, 1 ]
          ^-->
[ 7, 6, 5, | 1 ]

最后,當(dāng)序列中“未排序部分”只有一個(gè)元素的時(shí)候制肮,實(shí)際上整個(gè)序列就已經(jīng)全部排序完成了冒窍。

實(shí)現(xiàn)

理解和選擇排序的核心思想之后,實(shí)現(xiàn)的部分就很簡(jiǎn)單了豺鼻。首先是和插入排序類似的“套路聲明”:

typealias Criteria<T> = (T, T) -> Bool
func SelectionSortOf<T: Comparable>(_ coll: Array<T>,
                    byCriteria: Criteria<T> = { $0 > $1 }) -> Array<T> { 

   guard coll.count > 1 else { return coll } 

   var result = coll 

   // TODO: add implementation here 
   return result
}

關(guān)于聲明中和Swift 3相關(guān)的內(nèi)容综液,大家可以參考插入排序中的相關(guān)說(shuō)明,我們就不再重復(fù)了儒飒。直接來(lái)看實(shí)現(xiàn)谬莹。
首先,遍歷數(shù)組中的 0 - (N-1) 元素桩了,每一次迭代届良,都表示把豎線右移,在“未排序部分”找下一個(gè)要交換的元素圣猎,在執(zhí)行真正的交換前士葫,我們先打印了序列的“已排序”和“未排序”部分;

// 1. Increase the sorted sub array
for x in 0 ..< coll.count - 1 {
    var candidateIndex = x 
    
    print("--------------------------")  
    print("Sorted:\t\(result[0 ..< candidateIndex])") 
    print("Unsorted:\t\(result[candidateIndex ..< result.count])")
}

其次送悔,我們?cè)偾短滓粋€(gè)for循環(huán)慢显,用于在“未排序部分”尋找下一個(gè)要交換的元素:

// 1. Increase the sorted sub array
for x in 0 ..< coll.count - 1 { 
    var candidateIndex = x 
    print("--------------------------") 
    print("Sorted:\t\(result[0 ..< candidateIndex])") 
    print("Unsorted:\t\(result[candidateIndex ..< result.count])")
    
    // 2. Find the next element to be moved into the sorted portion 
    for y in x + 1 ..< coll.count { 
        if byCriteria(result[candidateIndex], result[y]) { 
           candidateIndex = y 
        } 
   }
}

第三,找到后欠啤,由于Swift不允許交換同一個(gè)位置的元素荚藻,我們需要判斷下“待移進(jìn)已排序數(shù)組”中的元素是否需要交換:

// 1. Increase the sorted sub array
for x in 0 ..< coll.count - 1 { 
    var candidateIndex = x 
    print("--------------------------") 
    print("Sorted:\t\(result[0 ..< candidateIndex])") 
    print("Unsorted:\t\(result[candidateIndex ..< result.count])") 
    
    // 2. Find the next element to be moved into the sorted portion
    for y in x + 1 ..< coll.count {
        if byCriteria(result[candidateIndex], result[y]) { 
            candidateIndex = y 
        } 
    } 

    // 3. Swap the candidate into sorted sub array if needed 
    print(">>> Move \(result[candidateIndex]) into the sorted portion") 
    if (candidateIndex != x) {  
        swap(&result[candidateIndex], &result[x])
    }
}

最后,當(dāng)除了最后一個(gè)元素之外的其他元素都已經(jīng)移進(jìn)“已排序”部分時(shí)洁段,整個(gè)序列就已經(jīng)排序完成了应狱,我們直接把result返回:

typealias Criteria<T> = (T, T) -> Bool
func SelectionSortOf<T: Comparable>(_ coll: Array<T>, 
                     byCriteria: Criteria<T> = { $0 > $1 }) -> Array<T> { 

     guard coll.count > 1 else { return coll } 
     var result = coll 
    
     // 1. Increase the sorted sub array 
     for x in 0 ..< coll.count - 1 {
         var candidateIndex = x 
         print("--------------------------") 
         print("Sorted:\t\(result[0 ..< candidateIndex])") 
         print("Unsorted:\t\(result[candidateIndex ..< result.count])")
        
         // 2. Find the next element to be moved into the sorted portion 
        for y in x + 1 ..< coll.count {
            if byCriteria(result[candidateIndex], result[y]) { 
                candidateIndex = y 
            } 
         } 

         // 3. Swap the candidate into sorted sub array if needed 
         print(">>> Move \(result[candidateIndex]) into the sorted portion") 
         if (candidateIndex != x) { 
             swap(&result[candidateIndex], &result[x])
        } 
    }
    return result
}

測(cè)試

用一開(kāi)始的[1, 5, 7, 6]來(lái)測(cè)試。
首先是默認(rèn)的升序排列:

let a: Array<Int> = [1, 5, 7, 6]
SelectionSortOf(a)
SelectionSortDesc
SelectionSortDesc

然后是自定義的降序排列:

let a: Array<Int> = [1, 5, 7, 6]
SelectionSortOf(a, byCriteria: <)
SelectionSortAsc
SelectionSortAsc

從這些結(jié)果里祠丝,我們就能看到選擇排序的執(zhí)行流程了疾呻。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末除嘹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子岸蜗,更是在濱河造成了極大的恐慌尉咕,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件璃岳,死亡現(xiàn)場(chǎng)離奇詭異年缎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)铃慷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)单芜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人犁柜,你說(shuō)我怎么就攤上這事洲鸠。” “怎么了赁温?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵坛怪,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我股囊,道長(zhǎng)袜匿,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任稚疹,我火速辦了婚禮居灯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘内狗。我一直安慰自己怪嫌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布柳沙。 她就那樣靜靜地躺著岩灭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赂鲤。 梳的紋絲不亂的頭發(fā)上噪径,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天,我揣著相機(jī)與錄音数初,去河邊找鬼找爱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛泡孩,可吹牛的內(nèi)容都是我干的车摄。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吮播!你這毒婦竟也來(lái)了变屁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤薄料,失蹤者是張志新(化名)和其女友劉穎敞贡,沒(méi)想到半個(gè)月后泵琳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體摄职,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年获列,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谷市。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡击孩,死狀恐怖迫悠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情巩梢,我是刑警寧澤创泄,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站括蝠,受9級(jí)特大地震影響鞠抑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜忌警,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一搁拙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧法绵,春花似錦箕速、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至徙赢,卻和暖如春字柠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背犀忱。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工募谎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人阴汇。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓数冬,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拐纱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)铜异、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,102評(píng)論 4 62
  • 概述 排序有內(nèi)部排序和外部排序秸架,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序揍庄,而外部排序是因排序的數(shù)據(jù)很大,一次不能容納全部...
    蟻前閱讀 5,183評(píng)論 0 52
  • 概述:排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序缘薛,而外部排序是因排序的數(shù)據(jù)很大燥透,一次不能容納全部...
    每天刷兩次牙閱讀 3,730評(píng)論 0 15
  • 今晨出發(fā)回京,出橫嶺食茎,下于田,穿萬(wàn)安馏谨,過(guò)泰和别渔,我在車(chē)上被顛得有些頭暈,但心境卻格外明朗——因?yàn)槲矣挚吹搅司眠`的油菜...
    拍岸閱讀 314評(píng)論 0 1
  • 我是一個(gè)山間長(zhǎng)大的女孩惧互,我們雖然窮哎媚,但一家和諧幸福,我媽給我起了一個(gè)好聽(tīng)的名字喊儡,叫星落拨与。可是管宵,在我18歲那年截珍,...
    夢(mèng)依雪閱讀 887評(píng)論 1 0