Skip to content

Commit 7be7b6f

Browse files
committed
Add general-purpose binary tree
1 parent 837934e commit 7be7b6f

10 files changed

+324
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//: Playground - noun: a place where people can play
2+
3+
public indirect enum BinaryTree<T> {
4+
case Node(BinaryTree<T>, T, BinaryTree<T>)
5+
case Empty
6+
7+
public var count: Int {
8+
switch self {
9+
case let .Node(left, _, right):
10+
return left.count + 1 + right.count
11+
case .Empty:
12+
return 0
13+
}
14+
}
15+
}
16+
17+
extension BinaryTree: CustomStringConvertible {
18+
public var description: String {
19+
switch self {
20+
case let .Node(left, value, right):
21+
return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]"
22+
case .Empty:
23+
return ""
24+
}
25+
}
26+
}
27+
28+
29+
30+
// leaf nodes
31+
let node5 = BinaryTree.Node(.Empty, "5", .Empty)
32+
let nodeA = BinaryTree.Node(.Empty, "a", .Empty)
33+
let node10 = BinaryTree.Node(.Empty, "10", .Empty)
34+
let node4 = BinaryTree.Node(.Empty, "4", .Empty)
35+
let node3 = BinaryTree.Node(.Empty, "3", .Empty)
36+
let nodeB = BinaryTree.Node(.Empty, "b", .Empty)
37+
38+
// intermediate nodes on the left
39+
let Aminus10 = BinaryTree.Node(nodeA, "-", node10)
40+
let timesLeft = BinaryTree.Node(node5, "*", Aminus10)
41+
42+
// intermediate nodes on the right
43+
let minus4 = BinaryTree.Node(.Empty, "-", node4)
44+
let divide3andB = BinaryTree.Node(node3, "/", nodeB)
45+
let timesRight = BinaryTree.Node(minus4, "*", divide3andB)
46+
47+
// root node
48+
let tree = BinaryTree.Node(timesLeft, "+", timesRight)
49+
50+
print(tree)
51+
tree.count // 12
52+
53+
54+
55+
extension BinaryTree {
56+
public func traverseInOrder(@noescape process: T -> Void) {
57+
if case let .Node(left, value, right) = self {
58+
left.traverseInOrder(process)
59+
process(value)
60+
right.traverseInOrder(process)
61+
}
62+
}
63+
64+
public func traversePreOrder(@noescape process: T -> Void) {
65+
if case let .Node(left, value, right) = self {
66+
process(value)
67+
left.traversePreOrder(process)
68+
right.traversePreOrder(process)
69+
}
70+
}
71+
72+
public func traversePostOrder(@noescape process: T -> Void) {
73+
if case let .Node(left, value, right) = self {
74+
left.traversePostOrder(process)
75+
right.traversePostOrder(process)
76+
process(value)
77+
}
78+
}
79+
}
80+
81+
//tree.traverseInOrder { s in print(s) }
82+
//tree.traversePreOrder { s in print(s) }
83+
tree.traversePostOrder { s in print(s) }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='osx'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Timeline
3+
version = "3.0">
4+
<TimelineItems>
5+
</TimelineItems>
6+
</Timeline>

Binary Tree/BinaryTree.swift

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
A general-purpose binary tree.
3+
4+
Nodes don't have a reference to their parent.
5+
*/
6+
public indirect enum BinaryTree<T> {
7+
case Node(BinaryTree<T>, T, BinaryTree<T>)
8+
case Empty
9+
10+
public var count: Int {
11+
switch self {
12+
case let .Node(left, _, right):
13+
return left.count + 1 + right.count
14+
case .Empty:
15+
return 0
16+
}
17+
}
18+
}
19+
20+
extension BinaryTree: CustomStringConvertible {
21+
public var description: String {
22+
switch self {
23+
case let .Node(left, value, right):
24+
return "value: \(value), left = [" + left.description + "], right = [" + right.description + "]"
25+
case .Empty:
26+
return ""
27+
}
28+
}
29+
}
30+
31+
extension BinaryTree {
32+
public func traverseInOrder(@noescape process: T -> Void) {
33+
if case let .Node(left, value, right) = self {
34+
left.traverseInOrder(process)
35+
process(value)
36+
right.traverseInOrder(process)
37+
}
38+
}
39+
40+
public func traversePreOrder(@noescape process: T -> Void) {
41+
if case let .Node(left, value, right) = self {
42+
process(value)
43+
left.traversePreOrder(process)
44+
right.traversePreOrder(process)
45+
}
46+
}
47+
48+
public func traversePostOrder(@noescape process: T -> Void) {
49+
if case let .Node(left, value, right) = self {
50+
left.traversePostOrder(process)
51+
right.traversePostOrder(process)
52+
process(value)
53+
}
54+
}
55+
}

Binary Tree/Images/BinaryTree.graffle

2.55 KB
Binary file not shown.

Binary Tree/Images/BinaryTree.png

12.9 KB
Loading

Binary Tree/Images/Operations.graffle

2.5 KB
Binary file not shown.

Binary Tree/Images/Operations.png

8.58 KB
Loading

Binary Tree/README.markdown

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
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+
![A binary tree](Images/BinaryTree.png)
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+
![A binary tree](Images/Operations.png)
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*

README.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ Often just using the built-in `Array`, `Dictionary`, and `Set` types is sufficie
134134
### Trees
135135

136136
- [Tree](Tree/). A general-purpose tree structure.
137-
- Binary Tree
137+
- [Binary Tree](Binary Tree/). A tree where each node has at most two children.
138138
- [Binary Search Tree (BST)](Binary Search Tree/). A binary tree with the special requirement that elements are inserted in a specific way, allowing for faster queries, like when using a [binary search](Binary Search/) algorithm.
139139
- AVL Tree
140140
- Red-Black Tree

0 commit comments

Comments
 (0)