Swift里的算法和数据结构

在这篇博客里,会教给大家如何实现一个Swift tree的数据结构。这是一个比较普遍而且有用的数据结构,也是你学习最好的一个开始。

翻译自:https://www.raywenderlich.com/138190/swift-algorithm-club-swift-tree-data-structure

Tree数据结构:

最简单的方式来理解Tree数据结构是通过一个图片:


上面的图显示出了Tree有五个Level,  root的level是0,接着,每深入一层,level便增加1.

Tree可以帮助你解决很多的重要问题, 包括:表示对象之间的层次关系,让搜索变的更有效快捷, 提供一个排序的列表数据, 为前缀匹配文本字段。

接下来,我们学习一些术语用来理解Tree.

Root: Root就是Tree指向Level 0的node,你可以把它认为是你Tree数据结构的进入点。


Node: 一个Node是一个数据块,在Tree结构中。 也就是这个节点中包含的数据是依靠这个Tree的类型。Root也是一个Node.


 Leaf : 一些情况下,指向的是一个末端节点node,一个leaf是一个简单的node节点没有children, 举个例子,如果node对象有left child,然后right child是nil空,那么你可以认为这个node就是一个leaf.

Tree在Swift里的实现:

在这一节里,你会实现一个一般用途的Tree. 这是一个没有任何限制的Tree,  (就像每个node会有多少的child, 多少节点nodes)

记住一点:每一个tree都是由nodes组成的。 所以开始之前,我们先建立一个基本的node类。创建一个新swift  playground, 然后添加下面的空类:

class Node {
 
}

Value: 你将要用到这个tree来管理字符串数据。 更新你的代码:

class Node {
  var value: String
 
  init(value: String) {
    self.value = value
  }
}

你定义了一个属性叫做value, 类型是string. 你还声明了一个初始值,是一个需要被初始化的属性。

Children: 对于children, 每一个node需要一些children.

更新你的类定义:

class Node {
  var value: String
  var children: [Node] = [] // add the children property
 
  init(value: String) {
    self.value = value
  }
}
你简单的声明了children是一个数组的node, 每一个child代表了一个node, 也就是level 1低一级的当前节点。

Parent: 有些时候,很快捷便利的是每一个node都有一个link指向它的parent node. Children是node下一级的节点, 而parent则是上一级的节点。 一个node只有一个parent, 但是可以有很多的children. 

更新你的node类代码:

class Node {
  var value: String
  var children: [Node] = []
  weak var parent: Node? // add the parent property
 
  init(value: String) {
    self.value = value
  }
}
记得,你设置了parent为optional. 这是因为不适所有的nodes都有parents. 就像root node就不是。

Insertion: 为了在tree中控制insertion, 你需要声明一个add(child:)方法,更新你的运行代码:

class Node {
  var value: String
  var children: [Node] = []
  weak var parent: Node?
 
  init(value: String) {
    self.value = value
  }
 
  func add(child: Node) {
    children.append(child)
    child.parent = self
  }
}

这个是最好的理解方式,来理解addChild()是怎样工作的,在你的类之外,写下面的代码:

let beverages = Node(value: "beverages")
 
let hotBeverages = Node(value: "hot")
let coldBeverages = Node(value: "cold")
 
beverages.add(child: hotBeverages)
beverages.add(child: coldBeverages)

多级结构是很常见的在数据结构中,所以当你定义3种不同的nodes,然后组织他们进入一个合理的层级。那么对应的结构应该如下图所示:


 Printing Trees: 打印输出trees

验证一个大型的tree结构是比较困难的,如果没有人和的控制台日志记录。在你定义了你的tree structure之后,登录控制台打印tree.

print(beverages) // <- try to print it!

你可以打开控制台按下组合键:Command+Shift+Y, 那么你可以看到你的类的名称打印到了控制台。

你需要让Node符合CustomStringConvertible的协议。 那么添加下面的代码到你的Node类中:

// 1
extension Node: CustomStringConvertible {
  // 2
  var description: String {
    // 3
    var text = "\(value)"
 
   // 4
    if !children.isEmpty {
      text += " {" + children.map { $0.description }.joinWithSeparator(", ") + "} "
    }
    return text
  }
}
这段代码是相对简单的:你声明一个扩展节点类,而你已经采用CustomStringConvertible协议。这个协议希望你实现一个计算的属性的名称描述,字符串类型。你已声明了描述属性。这是一个计算的属性,一个只读属性,它返回一个字符串。而且你已经声明了一个文本变量。现在,你给它当前节点的值。除了打印节点的当前值,您还需要打印的children,等等。这样做,你将会递归地将children描述,同时添加一些括号给字符串一些上下文关于children的结构。


现在,当你调用print 你的node类,你会得到下面的显示:

"beverages {hot {tea {black, green, chai} , coffee, cocoa} , cold {soda {ginger ale, bitter lemon} , milk} } \n"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值