|
| 1 | +# Binary Tree |
| 2 | + |
| 3 | +A binary tree is a [tree](../Tree/) where each node has 0, 1, or 2 children. This is a binary tree: |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +The child nodes are usually called the "left" child and the "right" child. If a node doesn't have any children, it's called a *leaf* node. The *root* is the node at the very top of the tree (programmers like their trees upside down). |
| 8 | + |
| 9 | +Often nodes will have a link back to their parent but this is not strictly necessary. |
| 10 | + |
| 11 | +Binary trees are often used as [binary search trees](../Binary Search Tree/). In that case, the nodes must be in a specific order (smaller values on the left, larger values on the right). But this is not a requirement for all binary trees. |
| 12 | + |
| 13 | +For example, here is a binary tree that represents a sequence of arithmetical operations, `(5 * (a - 10)) + (-4 * (3 / b))`: |
| 14 | + |
| 15 | + |
| 16 | + |
| 17 | +## The code |
| 18 | + |
| 19 | +Here's how you could implement a general-purpose binary tree in Swift: |
| 20 | + |
| 21 | +```swift |
| 22 | +public indirect enum BinaryTree<T> { |
| 23 | + case Node(BinaryTree<T>, T, BinaryTree<T>) |
| 24 | + case Empty |
| 25 | +} |
| 26 | +``` |
| 27 | + |
| 28 | +As an example of how to use this, let's build that tree of arithmetic operations: |
| 29 | + |
| 30 | +```swift |
| 31 | +// leaf nodes |
| 32 | +let node5 = BinaryTree.Node(.Empty, "5", .Empty) |
| 33 | +let nodeA = BinaryTree.Node(.Empty, "a", .Empty) |
| 34 | +let node10 = BinaryTree.Node(.Empty, "10", .Empty) |
| 35 | +let node4 = BinaryTree.Node(.Empty, "4", .Empty) |
| 36 | +let node3 = BinaryTree.Node(.Empty, "3", .Empty) |
| 37 | +let nodeB = BinaryTree.Node(.Empty, "b", .Empty) |
| 38 | + |
| 39 | +// intermediate nodes on the left |
| 40 | +let Aminus10 = BinaryTree.Node(nodeA, "-", node10) |
| 41 | +let timesLeft = BinaryTree.Node(node5, "*", Aminus10) |
| 42 | + |
| 43 | +// intermediate nodes on the right |
| 44 | +let minus4 = BinaryTree.Node(.Empty, "-", node4) |
| 45 | +let divide3andB = BinaryTree.Node(node3, "/", nodeB) |
| 46 | +let timesRight = BinaryTree.Node(minus4, "*", divide3andB) |
| 47 | + |
| 48 | +// root node |
| 49 | +let tree = BinaryTree.Node(timesLeft, "+", timesRight) |
| 50 | +``` |
| 51 | + |
| 52 | +You need to build up the tree in reverse, starting with the leaf nodes and working your way up to the top. |
| 53 | + |
| 54 | +It will be useful to add a `description` method so you can print the tree: |
| 55 | + |
| 56 | +```swift |
| 57 | +extension BinaryTree: CustomStringConvertible { |
| 58 | + public var description: String { |
| 59 | + switch self { |
| 60 | + case let .Node(left, value, right): |
| 61 | + return "value: \(value), left = [" + left.description + "], right = [" |
| 62 | + + right.description + "]" |
| 63 | + case .Empty: |
| 64 | + return "" |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +If you `print(tree)` you should see something like this: |
| 71 | + |
| 72 | + value: +, left = [value: *, left = [value: 5, left = [], right = []], right = [value: -, left = [value: a, left = [], right = []], right = [value: 10, left = [], right = []]]], right = [value: *, left = [value: -, left = [], right = [value: 4, left = [], right = []]], right = [value: /, left = [value: 3, left = [], right = []], right = [value: b, left = [], right = []]]] |
| 73 | + |
| 74 | +With a bit of imagination, you can see the tree structure. ;-) It helps if you indent it: |
| 75 | + |
| 76 | + value: +, |
| 77 | + left = [value: *, |
| 78 | + left = [value: 5, left = [], right = []], |
| 79 | + right = [value: -, |
| 80 | + left = [value: a, left = [], right = []], |
| 81 | + right = [value: 10, left = [], right = []]]], |
| 82 | + right = [value: *, |
| 83 | + left = [value: -, |
| 84 | + left = [], |
| 85 | + right = [value: 4, left = [], right = []]], |
| 86 | + right = [value: /, |
| 87 | + left = [value: 3, left = [], right = []], |
| 88 | + right = [value: b, left = [], right = []]]] |
| 89 | + |
| 90 | +Another useful method is counting the number of nodes in the tree: |
| 91 | + |
| 92 | +```swift |
| 93 | + public var count: Int { |
| 94 | + switch self { |
| 95 | + case let .Node(left, _, right): |
| 96 | + return left.count + 1 + right.count |
| 97 | + case .Empty: |
| 98 | + return 0 |
| 99 | + } |
| 100 | + } |
| 101 | +``` |
| 102 | + |
| 103 | +On the tree from the example, `tree.count` should be 12. |
| 104 | + |
| 105 | +Something you often need to do with trees is traverse them, i.e. look at all the nodes in some order. There are three ways to traverse a binary tree: |
| 106 | + |
| 107 | +1. *In-order* (or *depth-first*): first look at the left child node, then at the node itself, and finally at the right child. |
| 108 | +2. *Pre-order*: first look at a node, then its left and right children. |
| 109 | +3. *Post-order*: first look at the left and right children and process the node last. |
| 110 | + |
| 111 | +Here is how you'd implement that: |
| 112 | + |
| 113 | +```swift |
| 114 | + public func traverseInOrder(@noescape process: T -> Void) { |
| 115 | + if case let .Node(left, value, right) = self { |
| 116 | + left.traverseInOrder(process) |
| 117 | + process(value) |
| 118 | + right.traverseInOrder(process) |
| 119 | + } |
| 120 | + } |
| 121 | + |
| 122 | + public func traversePreOrder(@noescape process: T -> Void) { |
| 123 | + if case let .Node(left, value, right) = self { |
| 124 | + process(value) |
| 125 | + left.traversePreOrder(process) |
| 126 | + right.traversePreOrder(process) |
| 127 | + } |
| 128 | + } |
| 129 | + |
| 130 | + public func traversePostOrder(@noescape process: T -> Void) { |
| 131 | + if case let .Node(left, value, right) = self { |
| 132 | + left.traversePostOrder(process) |
| 133 | + right.traversePostOrder(process) |
| 134 | + process(value) |
| 135 | + } |
| 136 | + } |
| 137 | +``` |
| 138 | + |
| 139 | +As is common when working with tree structures, these functions call themselves recursively. |
| 140 | + |
| 141 | +For example, if you traverse the tree of arithmetic operations in post-order, you'll see the values in this order: |
| 142 | + |
| 143 | + 5 |
| 144 | + a |
| 145 | + 10 |
| 146 | + - |
| 147 | + * |
| 148 | + 4 |
| 149 | + - |
| 150 | + 3 |
| 151 | + b |
| 152 | + / |
| 153 | + * |
| 154 | + + |
| 155 | + |
| 156 | +The leaves appear first. The root node appears last. |
| 157 | + |
| 158 | +You can use a stack machine to evaluate these expressions, something like the following pseudocode: |
| 159 | + |
| 160 | +```swift |
| 161 | +tree.traversePostOrder { s in |
| 162 | + switch s { |
| 163 | + case this is a numeric literal, such as 5: |
| 164 | + push it onto the stack |
| 165 | + case this is a variable name, such as a: |
| 166 | + look up the value of a and push it onto the stack |
| 167 | + case this is an operator, such as *: |
| 168 | + pop the two top-most items off the stack, multiply them, |
| 169 | + and push the result back onto the stack |
| 170 | + } |
| 171 | + the result is in the top-most item on the stack |
| 172 | +} |
| 173 | +``` |
| 174 | + |
| 175 | +*Written for Swift Algorithm Club by Matthijs Hollemans* |
0 commit comments