Swift是苹果新推出的编程语言,也是苹果首个开源语言。相比于原来的Objective-C,Swift要更轻便和灵活。笔者最近使用Swift实践了大量的算法(绝大部分是硅谷各大公司的面试题),将心得体会总结于下。此文并不是纯粹讨论Swift如何实现某一个具体的算法或者数据结构,如冒泡排序、深度优先遍历,或是树和栈,而是总结归纳一些Swift常用的语法和技巧,以便大家在解决面试题中使用。

基本语法

先来看下面一段代码

func swap(chars:[Character],  p: Int, q: Int) {
var temp = chars[p]
chars[p] = chars[q]
chars[q] = temp
}
// Assume array is a character array and it has enough elements
swap(array, p: , q: )

上面代码实现了一个非常简单的功能,就是交换一个数组中的两个值。乍一看非常正确,实际上存在以下几个问题。

在第一个参数前应该加上 inout 关键字。因为在Swift中,struct都是按值传递,class是按引用传递;数组和字典都是struct。所以要改变原来的chars数组,在其前部加入inout关键字,表示是按引用传递。
p 和 q 之前应该加入下划线。Swift默认函数的第一个参数是局部(local)变量,而后续参数都是外部(external)变量,外部变量必须声明。如果在p和q前加上下划线,则在调用函数时无需声明外部变量,这样调用起来更简便。
temp前的var应该改为let。let用于声明常量(constant),var用于声明变量(variable)。swap函数中,temp并未进行修改,所以应当视为常量,用let来声明。

修改过后的代码为

func swap(inout chars:[Character],  _ p: Int, _ q: Int) {
let temp = chars[p]
chars[p] = chars[q]
chars[q] = temp
}
// Assume array is a character array and it has enough elements
swap(&array, , )

再来看一段代码

func toZero(x: Int) -> Int {
while x > {
x -=
}
return x
}

这里在 x -= 1 处会报错。原因是函数中所有的参数是常量(let),是不可以修改的。解决的方法是在函数中写上var x = x,之后就可以对 x 进行修改了

循环

Swift循环分为for和while两种,注意他们的结构跟传统的 Java, C/C++有很大区别,笔者将其总结如下

// Assume names is an array holds enough Strings
// for loop
for name in names { }
for i in ... names.count - { }
for i in ..< names.count { }
for _ in ..< names.count { }
for name in names.reverse() { }
for i in .stride(through: names.count - , by ) { }
for i in .stride(to: names.count, by: ) { } // while loop
var i =
while i < names.count { }
repeat { } while i < names.count

以上代码非常简单。需要说明的有两个,一个是 for _ in 0 ..< names.count { } 。当我们不需要数组中每一个具体的元素值时,我们就可以用下划线来代表序号。
另一个是是 repeat { } while i < names.count 。这个相当于我们熟悉(java)的 do { } while (i < names.length)。

排序

swift排序效率很高,写法也很简洁。笔者将其总结如下

// Sort an Int array,ascending
nums.sortInPlace({$ < $}) // Sort an Int array without mutating the original one, ascending
var sortedNums = nums.sort({$ < $}) // Sort an array with custom-defined objects, ascending
timeIntervals.sortInPlace({$.startTime < $.startTime}) // Sort keys in a dictionary according to its value, ascending
let keys = Array(dict.keys)
var sortedKeys = keys.sort() {
let value0 = dict[$]
let value1 = dict[$]
return value0 < value1
}

活用Guard语句

使用Guard语句可以让逻辑变得非常清楚,尤其是在处理算法问题的时候,请看下面的代码

// Returns the index of the first occurrence of needle in haystack,
// or -1 if needle is not part of haystack
func strStr(haystack: String, _ needle: String) -> Int {
var hChars = [Character](haystack.characters)
var nChars = [Character](needle.characters) if hChars.count < nChars.count {
return -
}
if hChars.count == {
return -
} for i in ... hChars.count - nChars.count {
if hChars[i] == nChars[] {
for j in ..< nChars.count {
if hChars[i + j] != nChars[j] {
break
} else {
if j == nChars.count - {
return i
}
}
}
}
}
return -
}

上面这段代码是求字符串needle在字符串haystack里首次出现的位置。我们发现for循环中的嵌套非常繁琐,但是如果使用Guard语句代码会变得清晰很多:

func strStr(haystack: String, _ needle: String) -> Int {
var hChars = [Character](haystack.characters)
var nChars = [Character](needle.characters) guard hChars.count >= nChars.count else {
return -
}
if nChars.count == {
return
} for i in ... hChars.count - nChars.count {
guard hChars[i] == nChars[] else {
continue
} for j in ..< nChars.count {
guard hChars[i + j] == nChars[j] else {
break
}
if j == nChars.count - {
return i
}
}
} return -
}

Guard语句的好处是判断条件永远是我们希望的条件而不是特殊情况,且成功避免了大量的if嵌套。

另外在上面代码中,为何要将字符串转化成数组进行处理?因为Swift中没有方法能够以O(1)的时间复杂度取得字符串中的字符,我们常用的string.startIndex.advancedBy(n)方法,其时间复杂度为O(n)。所以笔者在这里以空间换时间的方法进行了优化。
总结

Swift是一门独特的语言,本文对其基本知识和语法进行了适当归纳,文中提到的都是基本细节。下期我们会讨论更加进阶的内容。

Swift 算法实战之路:基本语法与技巧的更多相关文章

  1. Swift 算法实战之路:栈和队列

    这期的内容有点剑走偏锋,我们来讨论一下栈和队列.Swift语言中没有内设的栈和队列,很多扩展库中使用Generic Type来实现栈或是队列.笔者觉得最实用的实现方法是使用数组,本期主要内容有: 栈和 ...

  2. swift语言实战晋级-第9章 游戏实战-跑酷熊猫-7-8 移动平台的算法

    在上个小节,我们完成了平台的产生.那么我们来实现一下让平台移动.平台的移动,我们只需要在平台工厂类中写好移动的方法,然后在GameScene类中统一控制就行了. 在GameScene类中,有个upda ...

  3. Swift语言实战晋级

    Swift语言实战晋级基本信息作者: 老镇 丛书名: 爱上Swift出版社:人民邮电出版社ISBN:9787115378804上架时间:2014-12-26出版日期:2015 年1月开本:16开页码: ...

  4. swift语言实战晋级-第9章 游戏实战-跑酷熊猫-9-10 移除平台与视差滚动

    9.9 移除场景之外的平台 用为平台是源源不断的产生的,如果不注意销毁,平台就将越积越多,虽然在游戏场景中看不到.几十个还看不出问题,那几万个呢?几百万个呢? 所以我们来看看怎么移除平台,那什么样的平 ...

  5. Swift游戏实战-跑酷熊猫 08 产生源源不断的移动平台

    原理 代码实现 这节内容我们一起学习下平台的生产算法. 要点: 何时生成新的平台: 当上一个平台的右边完全进入场景的时候,就可以生成新的平台类. 如何知道上一个平台完全进入场景: 主场景中有个变量la ...

  6. Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-5-6 踩踏平台是怎么炼成的

    在游戏中,有很多分来飞去的平台,这个平台长短不一.如果每种长度都去创建一张图片那是比较繁琐的事情.实际上,我们只用到3张图.分别是平台的,平台的中间部分,平台的右边.关键是平台的中间部分,两张中间部分 ...

  7. Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-4 熊猫的跳和打滚

    之前我们学会了跑的动作,现在我们可以利用同样的方法来实现了跳和打滚的动画. …… class Panda : SKSpriteNode { …… //跳的纹理集合 let jumpAtlas = SK ...

  8. Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-3 显示一个动态的熊猫

    一个静态的熊猫明显不能满足我们的欲望,接下来我们就让熊猫跑起来.序列帧动画的原理就是不停的切换不同的图片.当我们将一张一张的切换Panda类的跑动文理后,熊猫就跑起来了.那么首先我们需要一个数组常量来 ...

  9. Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-2 创建熊猫类

    当我们创建好项目文件后我们就可以开始一步一步的按照我们之前列入的清单来编写我们的游戏.现在就让我们来创建一个熊猫这个类Panda.swift.我们将采取分解的方式,一步一步的完成Panda.swift ...

随机推荐

  1. Ubuntu 12.04 下安装配置 JDK 7(tar)

    第一步:下载jdk-7u45-linux-i586.tar.gz 到Orcale的JDK官网下载JDK7的tar包 第二步:解压安装 tar -zxvf ./jdk-7u45-linux-i586.t ...

  2. bzoj3864: Hero meet devil

    Description There is an old country and the king fell in love with a devil. The devil always asks th ...

  3. Comparing randomized search and grid search for hyperparameter estimation

    Comparing randomized search and grid search for hyperparameter estimation Compare randomized search ...

  4. KeilC51使用详解 (一)

    第一节 系统概述 Keil C51是美国Keil Software公司出品的51系列兼容单片机C语言软件开发系统,与汇编相比,C语言在功能上.结构性.可读性.可维护性上有明显的优势,因而易学易用.用过 ...

  5. Struts 2 标签

    注:要使用Strust 2标签需<%@ taglib prefix="s" uri="/struts-tags" %> 表单标签: .form标签 ...

  6. java学习面向对象之this

    在我们讲构造函数的时候,我们知道,如果同时在java的堆内存当中,同时存在好几个刚进内存,但是又没来得及初始化的同一个类的对象.在这种情况下,那么如何去区分栈内存当中的构造函数是属于那个对象的呢,其实 ...

  7. Unity NGUI中动态添加和删除sprite

    (以后,参考链接和作者将在文章首部给出,转载请保留此部分内容) 参考链接:http://www.narkii.com/club/thread-299977-1.html,作者:纳金网 比巴卜: 参考链 ...

  8. 日志式文件系统:SGI的xfs, Reiserfs, IBM的jfs, ext3fs

    日志文件(Log files)是包含系统消息的文件,包括内核.服务.在系统上运行的应用程序等.不同的日志文件记载不同的信息.日志文件系统比传统的文件系统安全,因为它用独立的日志文件跟踪磁盘内容的变化. ...

  9. Watch OS2.0开发概述

    (注:尊重劳动成果,转载请注明出处 http://www.cnblogs.com/xiaochunle/p/4620230.html ) Watch OS 2.0时代 北京时间2015年6月9日,WW ...

  10. MFC重绘函数:InvalidateRect(), Invalidate()和UpdateWindow()

    1. 重绘消息 当需要更新或者重绘窗口时,一般系统会发出两个消息WM_PAINT(通知客户区有变化)和WM_NCPAINT(通知非客户区有变化) WM_NCPAINT系统会自己搞定 WM_PAINT消 ...