通过算法了解Swift 3——“选择排序”

没有什么比数据结构和算法能更纯粹的展示一门编程语言的用法了。做为更具表现力、更加类型安全、支持多种编程范式的Swift 3,单纯理解语法上的变化是远远不够的,让我们通过一系列算法,从设计初衷到具体的语言实现,来感受这些Swift proposal吧。有些改变的确带了breaking change,但是,接受它们,你一定可以收获更多。

源自泊学

选择排序(Selection sort)

SelectionSort

Selection sort是一种和insertion sort类似的排序方法,它同样只适用于对规模不大的集合进行排序。
它的核心思想是,在序列内部,把序列逻辑上分成已排序和未排序两部分,不断找到未排序部分中最符合排序规则的元素,添加进已排序部分,直到序列中所有元素都已经添加到了已排序部分,此时,整个序列就排序完成了。
我们用数组[1, 5, 7, 6]进行降序排列来举例,整个过程是这样的:
1、我们用一个竖线来区分序列中“已排序”和“未排序”的部分,初始时,“已排序“部分为空,”未排序“部分是整个序列;

[ | 1, 5, 7, 6 ]

然后,第一个应该从“未排序部分”取出的元素,是7。把7和紧挨竖线右侧的数字交换,并且把竖线向右移动一个位置;

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

然后,继续从“未排序部分”取出元素6,它和5交换,并且把竖线移动一个位置:

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

接下来是5,交换它和1的位置,然后把竖线向右移动一个位置:

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

最后,当序列中“未排序部分”只有一个元素的时候,实际上整个序列就已经全部排序完成了。

实现

理解和选择排序的核心思想之后,实现的部分就很简单了。首先是和插入排序类似的“套路声明”:

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
}

关于声明中和Swift 3相关的内容,大家可以参考插入排序中的相关说明,我们就不再重复了。直接来看实现。
首先,遍历数组中的 0 - (N-1) 元素,每一次迭代,都表示把竖线右移,在“未排序部分”找下一个要交换的元素,在执行真正的交换前,我们先打印了序列的“已排序”和“未排序”部分;

// 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])")
}

其次,我们再嵌套一个for循环,用于在“未排序部分”寻找下一个要交换的元素:

// 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不允许交换同一个位置的元素,我们需要判断下“待移进已排序数组”中的元素是否需要交换:

// 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])
    }
}

最后,当除了最后一个元素之外的其他元素都已经移进“已排序”部分时,整个序列就已经排序完成了,我们直接把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
}

测试

用一开始的[1, 5, 7, 6]来测试。
首先是默认的升序排列:

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

从这些结果里,我们就能看到选择排序的执行流程了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • 概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    蚁前阅读 5,170评论 0 52
  • 概述:排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部...
    每天刷两次牙阅读 3,729评论 0 15
  • 今晨出发回京,出横岭,下于田,穿万安,过泰和,我在车上被颠得有些头晕,但心境却格外明朗——因为我又看到了久违的油菜...
    拍岸阅读 312评论 0 1
  • 我是一个山间长大的女孩,我们虽然穷,但一家和谐幸福,我妈给我起了一个好听的名字,叫星落。可是,在我18岁那年,...
    梦依雪阅读 883评论 1 0