Swift 算法实战之路:基本语法与技巧
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 算法实战之路:基本语法与技巧的更多相关文章
- Swift 算法实战之路:栈和队列
这期的内容有点剑走偏锋,我们来讨论一下栈和队列.Swift语言中没有内设的栈和队列,很多扩展库中使用Generic Type来实现栈或是队列.笔者觉得最实用的实现方法是使用数组,本期主要内容有: 栈和 ...
- swift语言实战晋级-第9章 游戏实战-跑酷熊猫-7-8 移动平台的算法
在上个小节,我们完成了平台的产生.那么我们来实现一下让平台移动.平台的移动,我们只需要在平台工厂类中写好移动的方法,然后在GameScene类中统一控制就行了. 在GameScene类中,有个upda ...
- Swift语言实战晋级
Swift语言实战晋级基本信息作者: 老镇 丛书名: 爱上Swift出版社:人民邮电出版社ISBN:9787115378804上架时间:2014-12-26出版日期:2015 年1月开本:16开页码: ...
- swift语言实战晋级-第9章 游戏实战-跑酷熊猫-9-10 移除平台与视差滚动
9.9 移除场景之外的平台 用为平台是源源不断的产生的,如果不注意销毁,平台就将越积越多,虽然在游戏场景中看不到.几十个还看不出问题,那几万个呢?几百万个呢? 所以我们来看看怎么移除平台,那什么样的平 ...
- Swift游戏实战-跑酷熊猫 08 产生源源不断的移动平台
原理 代码实现 这节内容我们一起学习下平台的生产算法. 要点: 何时生成新的平台: 当上一个平台的右边完全进入场景的时候,就可以生成新的平台类. 如何知道上一个平台完全进入场景: 主场景中有个变量la ...
- Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-5-6 踩踏平台是怎么炼成的
在游戏中,有很多分来飞去的平台,这个平台长短不一.如果每种长度都去创建一张图片那是比较繁琐的事情.实际上,我们只用到3张图.分别是平台的,平台的中间部分,平台的右边.关键是平台的中间部分,两张中间部分 ...
- Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-4 熊猫的跳和打滚
之前我们学会了跑的动作,现在我们可以利用同样的方法来实现了跳和打滚的动画. …… class Panda : SKSpriteNode { …… //跳的纹理集合 let jumpAtlas = SK ...
- Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-3 显示一个动态的熊猫
一个静态的熊猫明显不能满足我们的欲望,接下来我们就让熊猫跑起来.序列帧动画的原理就是不停的切换不同的图片.当我们将一张一张的切换Panda类的跑动文理后,熊猫就跑起来了.那么首先我们需要一个数组常量来 ...
- Swift语言实战晋级-第9章 游戏实战-跑酷熊猫-2 创建熊猫类
当我们创建好项目文件后我们就可以开始一步一步的按照我们之前列入的清单来编写我们的游戏.现在就让我们来创建一个熊猫这个类Panda.swift.我们将采取分解的方式,一步一步的完成Panda.swift ...
随机推荐
- C# 改变图片尺寸(压缩),Image Resize
/// <summary> /// Resize image with a directory as source /// </summary> /// <param n ...
- 关于 self 和 super 在oc 中 的疑惑 与 分析
关于 self 和 super 在oc 中 的疑惑 与 分析 面试一定都是很注重 基础的,不管高级还是初级. 虽然基础好跟基础不好都可以写 代码,网上那么多资料. 区分高低也就是研究的深度和广度 ...
- Unity干中学——如何实现类似Windows Store 应用程序和Android Toast的通知?
要实现通知中心功能,首先要创建一个游戏物体,在上面挂载GUITeture和GUIText脚本.注意GUITexture和GUIText脚本的顺序,GUITexture在前,GUIText在后,否则GU ...
- swfobject.js IE兼容问题
错误代码 在562行左右 / add style rule if (ua.ie && ua.win) { if (dynamicStylesheet && typeof ...
- 隐藏 response headers
1.response headers 为何物 从上图看到..这 透漏出服务器端 1.操作系统版本, IIS版本.开发语言 .以及.net framework 版本 虽然现在IIS 可以挂php .甚至 ...
- 登录远程SQL服务器
一 看ping 服务器IP能否ping通. 这个实际上是看和远程sql server 2000服务器的物理连接是否存在.如果不行,请检查网络,查看配置,当然得确保远程sql server 2000服务 ...
- BZOJ 1049 数字序列
Description 现在我们有一个长度为n的整数序列A.但是它太不好看了,于是我们希望把它变成一个单调严格上升的序列.但是不希望改变过多的数,也不希望改变的幅度太大. Input 第一行包含一个数 ...
- cf B Red and Blue Balls
思路:把字符串转化为一个二进制,遇到B就是一个数二进制中的1,答案就是这个数. #include <cstdio> #include <cstring> #include &l ...
- 牢记负载均衡与HA,高性能是不同的方案。一般的CLUSTER只能实现其中的一种,而ORACLE的RAC可以有两种。
F5/LVS<—Haproxy<—Squid/Varnish<—AppServer. 现在网站发展的趋势对网络负载均衡的使用是随着网站规模的提升根据不同的阶段来使用不同的技术: 第一 ...
- ExtJs + Struts2 + JSON
最近一直都在看EXTJS的东西,然后自己实践了下,界面倒是蛮漂亮的,但是一旦涉及到与服务器端进行数据互动麻烦就出来了,本来下了个例子确发现是 用DWR的,觉得我既然用了STRUTS2作为MVC的框架, ...