翻译自raywenderlich网站iOS教程Swift Algorithm Club系列算法
堆栈(Stack)就像数组,但功能有限。
堆栈提供LIFO或后进先出。 最后推动的元素是即将被推出的第一个元素。 (很是相似的数据结构,队列是FIFO,或先进先出。)swift
开始了解堆栈segmentfault
咱们用下面这堆书来模拟堆栈的工做方式
堆栈操做数组
push:想添加一个元素到堆栈上时,你能够推入堆栈。 你能够把它看做是在书堆上添加一本书。数据结构
peek:根据设计,堆栈不容许您检查其内容,但堆栈的顶层元素除外。 peek方法容许您检查堆栈顶部的内容。app
pop:当你想删除堆栈中的元素时,你从堆栈中弹出一个元素。 你可能会认为它是从书堆中拿走顶部的书籍。ide
Swift栈实现学习
打开一个playground开始实施Swift堆栈!
首先,将如下内容写入playground:测试
struct Stack { fileprivate var array: [String] = [] }
在这里已经声明了一个具备数组属性的Stack
。 下面咱们将与数组交互以实现push,pop和peek方法。网站
Push
将对象推入堆栈相对比较简单。 在Stack
中添加如下方法:
// 1 mutating func push(_ element: String) { // 2 array.append(element) }
Pop
弹出堆栈也很简单。 只需在push方法下,在Stack
中添加如下方法:
// 1 mutating func pop() -> String? { // 2 return array.popLast() }
String
。 返回类型是可选的,以处理堆栈空置的状况。 若是你尝试弹出一个空的堆栈,那么你会获得一个nil
。(popLast)
来删除它的最后一个元素 。Peek
查看堆栈只能查看堆栈的顶层元素。 Swift数组有一个最后一个属性。
func peek() -> String? { return array.last }
peek方法与pop方法很是类似。 除了名称以外,惟一的区别是peek避免了对数组内容进行操做,所以在这种状况下mutating关键字不是必需的。
开始测试
此时,Swift栈已准备好。 在playground的下面写下如下内容:
// 1 var rwBookStack = Stack() // 2 rwBookStack.push("3D Games by Tutorials") // 3 rwBookStack.peek() // 4 rwBookStack.pop() // 5 rwBookStack.pop()
在playground的右侧面板上,能够看到每行的结果:
rwBookStack
属性,并用Stack
来初始化它。 这须要是一个变量而不是一个常量,由于下面咱们须要改变栈的内容。PUSH
了一个字符串。PEEK
堆栈会看到“3D Games by Tutorials”
,这是你PUSH
堆栈的最后一个元素。POP
堆栈“3D Games by Tutorials”
,这是推入堆栈的最后一个元素。POP
堆栈中的全部内容时,显示nil
。自定义字符串转换
目前,很难直观地看到堆栈中的元素。 可是Swift有一个名为CustomStringConvertible
的内置协议,容许您定义如何以字符串表示对象。 在Stack
实现下面写下如下内容(不是在Stack
里面):
// 1 extension Stack: CustomStringConvertible { // 2 var description: String { // 3 let topDivider = "-----Stack---\n" let bottomDivider = "\n----------\n" // 4 let stackElements = array.reversed().joined(separator: "\n") // 5 return topDivider + stackElements + bottomDivider } }
CustomStringConvertible
,您能够建立一个扩展并采用CustomStringConvertible
协议。description
属性是CustomStringConvertible
协议必须的。joined(separator: "\n")
方法简单地使用数组中的每一个元素,并在每一个元素之间使用分隔符将它们链接在一块儿。例如,数组[“3D Games by Tutorials”,“tvOS Apprentice”]
将在加入后成为"3D Games by Tutorials\n tvOS Apprentice"
。description
返回删除以前的测试代码并在playground底部写下如下内容:
var rwBookStack = Stack() rwBookStack.push("3D Games by Tutorials") rwBookStack.push("tvOS Apprentice") rwBookStack.push("iOS Apprentice") rwBookStack.push("Swift Apprentice") print(rwBookStack)
控制台显示堆栈的正确表示形式:
-----Stack--- Swift Apprentice iOS Apprentice tvOS Apprentice 3D Games by Tutorials ----------
泛型
目前,Stack
只能存储字符串。 若是想建立一个堆栈来存储整数,咱们须要实现一个全新的堆栈。 幸运的是,Swift提供了更便捷的方法,首先,将Stack
的声明更新为如下内容:
struct Stack<Element> { // ... }
<>
将结构声明为泛型,容许堆栈将其用于全部类型。 接下来,查找并更新您写下“String”的全部实例,并将其替换为“Element”。 Stack
应该是这样的:
struct Stack<Element> { fileprivate var array: [Element] = [] // 1 mutating func push(_ element: Element) { // 2 array.append(element) } // 1 mutating func pop() -> Element? { // 2 return array.popLast() } func peek() -> Element? { return array.last } }
最后,你必须更新description
属性。 只有一个改变。 更新如下行以匹配如下内容:
// previous let stackElements = array.reversed().joined(separator: "\n") // now let stackElements = array.map { "\($0)" }.reversed().joined(separator: "\n")
上面是将它们链接在一块儿以前将数组中的元素转换为String。 因为您的堆栈如今是通用的,所以您没法肯定要加入的值是字符串。
最后,找到初始化你的堆栈的行:
var rwBookStack = Stack<String>()
如今,Stack
能够专用于全部类型,不管是String
,Int
,仍是您建立的自定义类型,例如Person
对象!
完成
还有两个其余属性一般与堆栈一块儿出现。 一般状况下,您想知道堆栈是否为空,以及当前堆栈中有多少元素。 在堆栈中添加如下计算属性:
var isEmpty: Bool { return array.isEmpty } var count: Int { return array.count }
到此这个练习已经结束。
以上是本人在raywenderlich学习时为方便本身,用谷歌翻译作的一个记录。
本系列其余文章:
Swift算法俱乐部:Swift队列数据结构(Queue)