通过算法了解Swift 3—插入排序

本文介绍了一种使用Swift3实现的插入排序算法,包括其基本思想、实现细节及测试过程。该算法允许用户指定排序规则,并能适用于包含任何可比较元素的数组。

Algorithms in Swift 3

Insertion sort

源自国内开发者喜爱的泊学网

插入排序是最基础的排序算法之一。它最核心的思想,由以下几条构成。当我们要对一个值为[1, 5, 6]
的数组从大到小排列时:
1.把序列的第一个元素想象成一个“子序列”[1],它是已经排序的;
2.按照既定的排序规则,把由序列的前两个元素构成的“子序列”排序:[5, 1]
3.之后,读入6,在之前已经排序好的“子序列”中,从右向左逐个和新读入的元素进行比对。如果满足排序规则,就交换已排序数组中的元素和待排序的元素:

[5, 1, 6] 
    ^ 6 > 1 == true
[5, 1, 6] 
    <---> 
     swap
[5, 6, 1]

简单来说,就是不断通过比对,移动待排序元素的位置。直到待排序元素和之前已排序“子序列”全部元素都比对完之后:

[5, 6, 1] 
 ^ 6 > 5 == true 
[5, 6, 1] 
 <---> 
  swap
[6, 5, 1]

新形成的序列就已经是排序好的了。(当然,这里也有一个潜台词,就是如果和子序列中第一个元素比对之后不需要移动,则新添加进来的元素就应该直接添加到子序列末尾);
- 反复3的操作,当读完所有待排序的元素之后,整个序列就排序完成了;

在理解插入排序的时候,要时刻记住一件事情:元素的操作永远只发生在相邻的两个元素之间。当我们在头脑中执行插入排序时,偶尔会忘记这条,会想着是否存在着跨元素交换的情况,然后就把自己搞晕了。

实现

如何使用?

在实现之前,我们要先考虑下开发者会如何使用这个算法,例如这样:

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

或者,我们允许用户指定一个排序方法

let a: Array<Int> = [1, 5, 6]
insertionSortOf(a, byCriteria: >) // [6, 5, 1]

然后,我们还应该允许对包含任何“可比较”元素的Array进行排序。于是,insertionSort
的声明可以是下面这样的。


如何按Swift 3的方式声明

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

在这个声明里,有以下和Swift 3相关的说明:
首先,我们使用了SE-0048中的新特性,**允许在typealias
中使用泛型参数**;
其次,在方法的命名上,我们参考了SE-0023 API设计指南中的要求:
“如果方法中第一个参数和方法名一起形成了一个语法正确的短语,去掉第一个参数的label,并且把参数label放到方法名中”
因此,我们把“表示要排序的集合”使用的介词“of”,从第一个参数名,放到了函数名中。
第三,在Swift 3里,根据SE-0046中的提议,函数的第一个参数不再默认省略label,它将和其他参数一样拥有默认的label行为。因此,如果我们要省略label,必须在参数名前强制使用_
。因此,在声明里,我们需要强制省略第一个参数的label。
第四,根据SE-0023 API设计指南中的要求:
- 要让方法调用时,形成语法正确的英文短语:因此,我们让第二个表示自定义比较规则的参数名为byCriteria

- 要为方法中的closure参数设置label:因此,我们没有去掉第二个closure参数的label;
- 当方法的参数在绝大多数时候使用相同值时,应为它指定默认值:因此,我们让byCriteria
的默认行为是按升序排列;


实现insertionSort

按照一开始我们在算法思路中的描述,在insertionSort
中添加下面的代码:
首先,只有一个元素的数组是无需排序的,我们直接返回就好:

func insertionSortOf<T: Comparable>( 
        _ coll: Array<T>, 
        byCriteria: CRITERIA<T> = { $0 < $1 }) -> Array<T> { 

    // 1. An array with a single element is ordered 
     guard coll.count > 1 else { 
         return coll 
    }
}

其次,复制一份参数数组,用于在函数内部进行排序:

func insertionSortOf<T: Comparable>(
        _ coll: Array<T>, 
        byCriteria: CRITERIA<T> = { $0 < $1 }) -> Array<T> { 

    //: #### 1. An array with a single element is ordered
    guard coll.count > 1 else { 
        return coll
    } 
    var result = coll
}

第三,我们从数组中第二个元素开始,通过逐个比对,来不断形成已排序好的子数组:

for x in 1 ..< coll.count { 
    var = x
    let key = result[y]

    print("Get: \(key)") 

    // 2. If the key needs to swap in the previous ordered sub array 
    while y > 0 && byCriteria(key, result[y - 1]) { 
          print("-----------------------------") 
          print("Remove: \(result[y]) at pos: \(y)") 
          print("Insert: \(key) at pos: \(y - 1)") 
          print("-----------------------------") 

          // 3. Swap the value 
          // The new Swift 3 API: 
          // remove(at:) replaces removeAtIndex
          // You can also use swap(:) instead of remove and insert. 
          result.remove(at: y) 
          result.insert(key, at: y - 1) 
          y -= 1 
     }
}

最后,数组中所有的元素都遍历之后,整个数组就完成排序了,我们直接把排序后的数组返回:

func insertionSortOf<T: Comparable>(
       _ coll: Array<T>, 
       byCriteria: CRITERIA<T> = { $0 < $1 }) -> Array<T> { 

    guard coll.count > 1 else { 
       return coll 
    } 

    var result = coll 

    for x in 1 ..< coll.count { 
        var y = x 
        let key = result[y] 

        print("Get: \(key)") 

        // 2. If the key needs to swap in the previous ordered sub array 
        while y > 0 && byCriteria(key, result[y - 1]) { 
            print("-----------------------------") 
            print("Remove: \(result[y]) at pos: \(y)") 
            print("Insert: \(key) at pos: \(y - 1)") 
            print("-----------------------------") 

            // 3. Swap the value 
            // Notice the new Swift 3 API: remove(at:) replaces removeAtIndex 
            // You can also use swap(:) instead of remove and insert 
            result.remove(at: y)
            result.insert(key, at: y - 1) 

           y -= 1 
       }
    } 
    // 4. Return the sorted array 
return result
}

测试

用一开始我们设计的使用方法来测试insertionSort

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

由于默认就是从小到大排序,并且,原始数组本身就是已经排序的,因此,我们可以在控制台看到下面的结果:
sorted array

如果我们传递一个自定义的比较规则,例如从大到小排序:

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

就可以在控制台看到这样的结果:
sorted array

数字5经历了一次交换,数字6经历了两次交换。


Have a try?

不用交换元素的插入排序方法

除了使用remove&insertswap
之外,还有一种插入排序的手段。用之前的[1, 5, 6]
降序排列举例。假设算法执行到了读入数字6:

1.记录读入的值:

[5, 1, 6] 
       ^ --> remember 6

2.在新读入位置前已排序好的子数组里,不断用前一个数字覆盖后一个位置,为新读入的元素找到合适的位置:

[5, 1, 1]
     --> shift 1 right
[5, 5, 1] 
     --> shift 5 right
[6, 5, 1] 
 ^ --> Copy 6 here

不同的实现方法之间的性能差异有多大呢?

  • insert&remove
  • swap
  • 以及我们最后提到的移动元素;

当移动大量元素时,这些算法之间的差异有多大呢?自己试验一下吧,欢迎大家把实验的结果贴到泊学视频下面的泊学Disqus论坛里。 :-)

3D应力敏感度分析拓扑优化】【基于p-范数全局应力衡量的3D敏感度分析】基于伴随方的有限元分析和p-范数应力敏感度分析(Matlab代码实现)内容概要:本文档介绍了基于伴随方的有限元分析与p-范数全局应力衡量的3D应力敏感度分析,并结合拓扑优化技术,提供了完整的Matlab代码实现方案。该方通过有限元建模计算结构在载荷作用下的应力分布,采用p-范数对全局应力进行有效聚合,避免传统方中应力约束过多的问题,进而利用伴随高效求解设计变量对应力的敏感度,为结构优化提供关键梯度信息。整个流程涵盖了从有限元分析、应力评估到敏感度计算的核心环节,适用于复杂三维结构的轻量化与高强度设计。; 适合人群:具备有限元分析基础、拓扑优化背景及Matlab编程能力的研究生、科研人员与工程技术人员,尤其适合从事结构设计、力学仿真与多学科优化的相关从业者; 使用场景及目标:①用于实现高精度三维结构的应力约束拓扑优化;②帮助理解伴随在敏感度分析中的应用原理与编程实现;③服务于科研复现、论文写作与工程项目中的结构性能提升需求; 阅读建议:建议读者结合有限元理论与优化算法知识,逐步调试Matlab代码,重点关注伴随方程的构建与p-范数的数值处理技巧,以深入掌握方本质并实现个性化拓展。
下载前必看:https://pan.quark.cn/s/9f13b242f4b9 Android 平板设备远程操控个人计算机的指南 Android 平板设备远程操控个人计算机的指南详细阐述了如何运用 Splashtop Remote 应用程序达成 Android 平板设备对个人计算机的远程操控。 该指南被划分为四个环节:首先,在个人计算机上获取并部署 Splashtop Remote 应用程序,并设定客户端密码;其次,在 Android 平板设备上获取并部署 Splashtop Remote 应用程序,并与之建立连接至个人计算机的通道;再次,在 Splashtop Remote 应用程序中识别已部署个人计算机端软件的设备;最后,运用平板设备对个人计算机实施远程操控。 关键点1:Splashtop Remote 应用程序的部署与配置* 在个人计算机上获取并部署 Splashtop Remote 应用程序,可通过官方网站或其他获取途径进行下载。 * 部署结束后,必须输入客户端密码,该密码在平板控制计算机时用作验证,密码长度至少为8个字符,且需包含字母与数字。 * 在配置选项中,能够设定是否在设备启动时自动运行客户端,以及进行互联网搜索设置。 关键点2:Splashtop Remote 应用程序的 Android 版本获取与部署* 在 Android 平板设备上获取并部署 Splashtop Remote 应用程序,可通过 Google Play Store 或其他获取途径进行下载。 * 部署结束后,必须输入客户端密码,该密码用于连接至个人计算机端软件。 关键点3:运用 Splashtop Remote 远程操控个人计算机* 在 Splashtop Remote 应用程序中识别...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值