前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swift算法俱乐部:Swift栈(Stack)数据结构

Swift算法俱乐部:Swift栈(Stack)数据结构

作者头像
Charlie_W
发布2018-10-19 14:55:39
1.7K0
发布2018-10-19 14:55:39
举报
文章被收录于专栏:Charlie's Road

翻译自raywenderlich网站iOS教程Swift Algorithm Club系列

堆栈(Stack)就像数组,但功能有限。

堆栈提供LIFO或后进先出。 最后推进的元素是即将被推出的第一个元素。 (非常类似的数据结构,队列是FIFO,或先进先出。)

开始了解堆栈

我们用下面这堆书来模拟堆栈的工作方式

堆栈操作

push:想添加一个元素到堆栈上时,你可以推入堆栈。 你可以把它看作是在书堆上添加一本书。

peek:根据设计,堆栈不允许您检查其内容,但堆栈的顶层元素除外。 peek方法允许您检查堆栈顶部的内容。

pop:当你想删除堆栈中的元素时,你从堆栈中弹出一个元素。 你可能会认为它是从书堆中拿走顶部的书籍。

Swift栈实现

打开一个playground开始实施Swift堆栈!

首先,将以下内容写入playground:

代码语言:javascript
复制
struct Stack {
    fileprivate var array: [String] = []
}

在这里已经声明了一个具有数组属性的Stack。 下面我们将与数组交互以实现push,pop和peek方法。

Push

将对象推入堆栈相对比较简单。 在Stack中添加以下方法:

代码语言:javascript
复制
// 1
mutating func push(_ element: String) {
    // 2
    array.append(element)
}
  1. push方法接受一个参数,并将元素添加到栈顶。
  2. 注意,push操作会将新元素放在数组的末尾,而不是开始。 在数组的开头插入代价很昂贵,因为它需要所有现有的数组元素在内存中移位。 最后加上O(1); 无论数组大小如何,它总是需要相同的时间。

Pop

弹出堆栈也很简单。 只需在push方法下,在Stack中添加以下方法:

代码语言:javascript
复制
// 1
mutating func pop() -> String? {
    // 2
    return array.popLast()
}
  1. pop方法返回一个可选的String。 返回类型是可选的,以处理堆栈空置的情况。 如果你尝试弹出一个空的堆栈,那么你会得到一个nil
  2. Swift数组有一个方便的方法(popLast)来删除它的最后一个元素 。

Peek

查看堆栈只能查看堆栈的顶层元素。 Swift数组有一个最后一个属性。

代码语言:javascript
复制
func peek() -> String? {
    return array.last
}

peek方法与pop方法非常相似。 除了名称之外,唯一的区别是peek避免了对数组内容进行操作,因此在这种情况下mutating关键字不是必需的。

开始测试

此时,Swift栈已准备好。 在playground的下面写下以下内容:

代码语言:javascript
复制
// 1
var rwBookStack = Stack()

// 2
rwBookStack.push("3D Games by Tutorials")
// 3
rwBookStack.peek()

// 4
rwBookStack.pop()
// 5
rwBookStack.pop()

在playground的右侧面板上,可以看到每行的结果:

  1. 声明了一个rwBookStack属性,并用Stack来初始化它。 这需要是一个变量而不是一个常量,因为下面我们需要改变栈的内容。
  2. 在堆栈中PUSH了一个字符串。
  3. PEEK堆栈会看到“3D Games by Tutorials”,这是你PUSH堆栈的最后一个元素。
  4. POP堆栈“3D Games by Tutorials”,这是推入堆栈的最后一个元素。
  5. POP堆栈中的所有内容时,显示nil

自定义字符串转换

目前,很难直观地看到堆栈中的元素。 但是Swift有一个名为CustomStringConvertible的内置协议,允许您定义如何以字符串表示对象。 在Stack实现下面写下以下内容(不是在Stack里面):

代码语言:javascript
复制
// 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
    }
}
  1. 要利用CustomStringConvertible,您可以创建一个扩展并采用CustomStringConvertible协议。
  2. 实现description属性是CustomStringConvertible协议必须的。
  3. 为了打印的美观加上----和换行
  4. 由于您已将元素附加到数组后面,因此您需要先倒转数组。之后用joined(separator: "\n")方法简单地使用数组中的每个元素,并在每个元素之间使用分隔符将它们连接在一起。例如,数组[“3D Games by Tutorials”,“tvOS Apprentice”]将在加入后成为"3D Games by Tutorials\n tvOS Apprentice"
  5. 最后,将夹层元素夹在两个分隔符之间,并将结果作为堆栈的description返回

删除之前的测试代码并在playground底部写下以下内容:

代码语言:javascript
复制
var rwBookStack = Stack()
rwBookStack.push("3D Games by Tutorials")
rwBookStack.push("tvOS Apprentice")
rwBookStack.push("iOS Apprentice")
rwBookStack.push("Swift Apprentice")
print(rwBookStack)

控制台显示堆栈的正确表示形式:

代码语言:javascript
复制
-----Stack---
Swift Apprentice
iOS Apprentice
tvOS Apprentice
3D Games by Tutorials
----------

泛型

目前,Stack只能存储字符串。 如果想创建一个堆栈来存储整数,我们需要实现一个全新的堆栈。 幸运的是,Swift提供了更便捷的方法,首先,将Stack的声明更新为以下内容:

代码语言:javascript
复制
struct Stack<Element> {
  // ...
}

<>将结构声明为泛型,允许堆栈将其用于所有类型。 接下来,查找并更新您写下“String”的所有实例,并将其替换为“Element”。 Stack应该是这样的:

代码语言:javascript
复制
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属性。 只有一个改变。 更新以下行以匹配以下内容:

代码语言:javascript
复制
// previous
let stackElements = array.reversed().joined(separator: "\n")

// now
let stackElements = array.map { "\($0)" }.reversed().joined(separator: "\n")

上面是将它们连接在一起之前将数组中的元素转换为String。 由于您的堆栈现在是通用的,因此您无法确定要加入的值是字符串。

最后,找到初始化你的堆栈的行:

代码语言:javascript
复制
var rwBookStack = Stack<String>()

现在,Stack可以专用于所有类型,无论是StringInt,还是您创建的自定义类型,例如Person对象!

完成

还有两个其他属性通常与堆栈一起出现。 通常情况下,您想知道堆栈是否为空,以及当前堆栈中有多少元素。 在堆栈中添加以下计算属性:

代码语言:javascript
复制
var isEmpty: Bool {
  return array.isEmpty
}

var count: Int {
  return array.count
}

到此这个练习已经结束。

以上是本人在raywenderlich学习时为方便自己,用谷歌翻译做的一个记录。

本系列其他文章:

Swift算法俱乐部:Swift队列数据结构(Queue)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档