【译】Swift算法俱乐部-树

栏目: Swift · 发布时间: 5年前

内容简介:本文是对:octopus:本文的翻译原文和代码可以查看:octopus:

本文是对 Swift Algorithm Club 翻译的一篇文章。 Swift Algorithm Club 是raywenderlich.com网站出品的用Swift实现算法和数据结构的开源项目,目前在GitHub上有18000+:star:️,我初略统计了一下,大概有一百左右个的算法和数据结构,基本上常见的都包含了,是iOSer学习算法和数据结构不错的资源。

:octopus: andyRon/swift-algorithm-club-cn 是我对Swift Algorithm Club,边学习边翻译的项目。由于能力有限,如发现错误或翻译不妥,请指正,欢迎pull request。也欢迎有兴趣、有时间的小伙伴一起参与翻译和学习 。当然也欢迎加:star:️, 。

本文的翻译原文和代码可以查看:octopus: swift-algorithm-club-cn/Tree

这个话题已经有个辅导文章

树表示对象之间的层次关系。 这是一个树的结构:

【译】Swift算法俱乐部-树

树由节点组成,这些节点彼此连接。

节点可以连接到他们的子节点,也可以连接到他们的父节点。 子节点是给定节点下的节点; 父节点是上面的节点。 节点始终只有一个父节点,但可以有多个子节点。

【译】Swift算法俱乐部-树

没有父节点的节点是 root 节点。 没有子节点的节点是 leaf 节点。

树中的指针不能形成循环。 这不是树:

【译】Swift算法俱乐部-树

这种结构称为 。 树实际上是一种非常简单的图形形式。 (类似地, 链表 是树的简单版本。想一想!)

本文讨论通用树。 通用树对每个节点可能有多少个子节点或树中节点的顺序没有任何限制。

这是在Swift中的基本实现:

public class TreeNode<T> {
  public var value: T

  public weak var parent: TreeNode?
  public var children = [TreeNode<T>]()

  public init(value: T) {
    self.value = value
  }

  public func addChild(_ node: TreeNode<T>) {
    children.append(node)
    node.parent = self
  }
}
复制代码

这描述了树中的单个节点。 它包含泛型类型 T ,对 parent 节点的引用,以及子节点数组。

添加 description 以便打印树:

extension TreeNode: CustomStringConvertible {
  public var description: String {
    var s = "\(value)"
    if !children.isEmpty {
      s += " {" + children.map { $0.description }.joined(separator: ", ") + "}"
    }
    return s
  }
}
复制代码

在 playground 创建树:

let tree = TreeNode<String>(value: "beverages")

let hotNode = TreeNode<String>(value: "hot")
let coldNode = TreeNode<String>(value: "cold")

let teaNode = TreeNode<String>(value: "tea")
let coffeeNode = TreeNode<String>(value: "coffee")
let chocolateNode = TreeNode<String>(value: "cocoa")

let blackTeaNode = TreeNode<String>(value: "black")
let greenTeaNode = TreeNode<String>(value: "green")
let chaiTeaNode = TreeNode<String>(value: "chai")

let sodaNode = TreeNode<String>(value: "soda")
let milkNode = TreeNode<String>(value: "milk")

let gingerAleNode = TreeNode<String>(value: "ginger ale")
let bitterLemonNode = TreeNode<String>(value: "bitter lemon")

tree.addChild(hotNode)
tree.addChild(coldNode)

hotNode.addChild(teaNode)
hotNode.addChild(coffeeNode)
hotNode.addChild(chocolateNode)

coldNode.addChild(sodaNode)
coldNode.addChild(milkNode)

teaNode.addChild(blackTeaNode)
teaNode.addChild(greenTeaNode)
teaNode.addChild(chaiTeaNode)

sodaNode.addChild(gingerAleNode)
sodaNode.addChild(bitterLemonNode)
复制代码

如果你打印出 tree 的值,你会得到:

beverages {hot {tea {black, green, chai}, coffee, cocoa}, cold {soda {ginger ale, bitter lemon}, milk}}
复制代码

这对应于以下结构:

【译】Swift算法俱乐部-树

beverages 节点是根节点,因为它没有父节点。 叶子是 黑色绿色咖啡可可姜汁苦柠檬牛奶 ,因为它们没有任何子节点。

对于任何节点,您可以查看 parent 属性, 并按照自己的方式返回到根:

teaNode.parent           // this is the "hot" node
teaNode.parent!.parent   // this is the root
复制代码

在谈论树时,我们经常使用以下定义:

  • 树的高度。 这是根节点和最低叶子之间的连接数。 在我们的示例中,树的高度为3,因为从根到底部需要三次跳转。

  • 节点的深度。此节点与根节点之间的连接数。 例如, tea 的深度为2,因为需要两次跳跃才能到达根部。 (根本身的深度为0.)

构建树的方法有很多种。 例如,有时您根本不需要 parent 属性。 或者,您可能只需要为每个节点提供最多两个子节点 - 这样的树称为 二叉树 。 一种非常常见的树类型是 二叉搜索树 (或BST),它是二叉树的更严格版本,其中节点以特定方式 排序 以加速搜索。

我在这里展示的通用树非常适合描述分层数据,但它实际上取决于您的应用程序需要具备哪种额外功能。

下面是一个如何使用 TreeNode 类来确定树是否包含特定值的示例。 首先看一下节点自己的 value 属性,如果没有匹配,那么依次看看这个节点所有的子节点。 当然,这些子节点也是 TreeNode ,所以它们将递归地重复相同的过程:首先看看它们自己的 value 属性,然后看看它们的子节点。 它们的子节点也会再次做同样的事情,等等...递归和树齐头并进。

这是代码:

extension TreeNode where T: Equatable {
  func search(_ value: T) -> TreeNode? {
    if value == self.value {
      return self
    }
    for child in children {
      if let found = child.search(value) {
        return found
      }
    }
    return nil
  }
}
复制代码

如何使用它的示例:

tree.search("cocoa")    // returns the "cocoa" node
tree.search("chai")     // returns the "chai" node
tree.search("bubbly")   // nil
复制代码

也可以使用数组来描述树。 数组中的索引表示不同的节点,然后,创建不同节点之间的连接。 例如,如果我们有:

0 = beverage    5 = cocoa		9  = green
1 = hot			6 = soda		10 = chai
2 = cold		7 = milk		11 = ginger ale
3 = tea			8 = black		12 = bitter lemon
4 = coffee								
复制代码

那么我们可以使用以下数组描述树:

[ -1, 0, 0, 1, 1, 1, 2, 2, 3, 3, 3, 6, 6 ]
复制代码

数组中的每个项的值都是指向其父节点的指针。索引3处的项 tea ,其值为1,因为其父项为 hot 。根节点指向 -1 ,因为它没有父节点。您只能将这些树从一个节点遍历到根节点,而不是相反。

顺便说一句,有时您会看到使用术语 forest 的算法。 显而易见,这是给予单独树对象集合的名称。 有关此示例,请参阅 union-find

作者:Matthijs Hollemans

翻译: Andy Ron

校对: Andy Ron


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

你凭什么做好互联网

你凭什么做好互联网

曹政 / 中国友谊出版公司 / 2016-12 / 42.00元

为什么有人可以预见商机、超越景气,在不确定环境下表现更出色? 在规则之外,做好互联网,还有哪些关键秘诀? 当环境不给机会,你靠什么翻身? 本书为“互联网百晓生”曹政20多年互联网经验的总结,以严谨的逻辑思维分析个人与企业在互联网发展中的一些错误思想及做法,并给出正确解法。 从技术到商业如何实现,每个发展阶段需要匹配哪些能力、分解哪些目标、落实哪些策略都一一点出,并在......一起来看看 《你凭什么做好互联网》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具