Skip to content

Commit 8fdc1af

Browse files
committed
Complete rough draft of Thread. Bin. Tree README
1 parent 692e49d commit 8fdc1af

File tree

1 file changed

+95
-21
lines changed

1 file changed

+95
-21
lines changed

Threaded Binary Tree/README.markdown

Lines changed: 95 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
A threaded binary tree is a special kind of [binary tree](../Binary Tree/) (a
44
tree in which each node has at most two children) that maintains a few extra
5-
variables to allow cheap and fast **in-order traversal** of the tree.
5+
variables to allow cheap and fast **in-order traversal** of the tree. We will
6+
explore the general structure of threaded binary trees, as well as
7+
[the Swift implementation](ThreadedBinaryTree.swift) of a fully functioning
8+
threaded binary tree.
69

710
If you don't know what a tree is or what it is for, then
811
[read this first](../Tree/).
@@ -11,14 +14,15 @@ If you don't know what a tree is or what it is for, then
1114
## In-order traversal
1215

1316
The main motivation behind using a threaded binary tree over a simpler and
14-
smaller standard binary tree is to increase the speed of **in-order traversal**
17+
smaller standard binary tree is to increase the speed of in-order traversal
1518
of the tree. An in-order traversal of a binary tree visits the nodes in the
1619
order in which they are stored, which matches the underlying ordering of a
1720
[binary search tree](../Binary Search Tree/). The idea is to visit all the
1821
left children of a node first, then visit the node itself, and visit the left
1922
children last.
2023

21-
In-order traversal of any binary tree generally goes as follows:
24+
In-order traversal of any binary tree generally goes as follows (using Swift
25+
syntax):
2226

2327
```swift
2428
func traverse(n: Node?) {
@@ -48,15 +52,15 @@ A threaded binary tree fixes this problem.
4852
## Predecessors and successors
4953

5054
An in-order traversal of a tree yields a linear ordering of the nodes. Thus
51-
each node has both a predecessor and a successor (except for the first and last
52-
nodes, which only have a successor or a predecessor respectively). In a
53-
threaded binary tree, each left child that would normally be `nil` instead
55+
each node has both a **predecessor** and a **successor** (except for the first
56+
and last nodes, which only have a successor or a predecessor respectively). In
57+
a threaded binary tree, each left child that would normally be `nil` instead
5458
stores the node's predecessor (if it exists), and each right child that would
5559
normally be `nil` instead stores the node's successor (if it exists). This is
5660
what separates threaded binary trees from standard binary trees.
5761

58-
There are two types of threaded binary trees: single threaded and double
59-
threaded:
62+
There are two types of threaded binary trees: **single threaded** and **double
63+
threaded**:
6064
- A single threaded tree keeps track of **either** the in-order predecessor
6165
**or** successor (left **or** right).
6266
- A double threaded tree keeps track of **both** the in-order predecessor
@@ -110,17 +114,18 @@ Swift *optionals*.
110114
- `leftThread: ThreadedBinaryTree?` is the in-order predecessor of this node
111115
- `rightThread: ThreadedBinaryTree?` is the in-order successor of this node
112116

113-
Now we are ready to go over some of the member functions in our
117+
As we are storing both `leftThread` and `rightThread`, this is a double
118+
threaded tree. Now we are ready to go over some of the member functions in our
114119
`ThreadedBinaryTree` class.
115120

116121

117122
## Traversal algorithm
118123

119124
Let's start with the main reason we're using a threaded binary tree. It is now
120125
very easy to find the in-order predecessor and the in-order successor of any
121-
node in the tree. If the node has no left/right child, we can simply return
122-
the node's leftThread/rightThread. Otherwise, it is trivial to move down the
123-
tree and find the correct node.
126+
node in the tree. If the node has no `left`/`right` child, we can simply
127+
return the node's `leftThread`/`rightThread`. Otherwise, it is trivial to move
128+
down the tree and find the correct node.
124129

125130
```swift
126131
func predecessor() -> ThreadedBinaryTree<T>? {
@@ -227,37 +232,104 @@ Let's start with the same tree that we used for the above traversal example:
227232

228233
![Base](Images/Base.png)
229234

230-
Suppose we `insert(10)` into this tree. The resulting graph would look like
235+
Suppose we insert **10** into this tree. The resulting graph would look like
231236
this, with the changes highlighted in red:
232237

233238
![Insert1](Images/Insert1.png)
234239

235240
If you've done your homework and are familiar with binary search trees, the
236-
placement of the node should not surprise you. What's new is how we maintain
237-
the threads between nodes.
241+
placement of this node should not surprise you. What's new is how we maintain
242+
the threads between nodes. So we know that we want to insert **10** as
243+
**12**'s `left` child. The first thing we do is set **12**'s `left` child to
244+
**10**, and set **10**'s `parent` to **12**. Because **10** is being inserted
245+
on the `left`, and **10** has no children of its own, we can safely set
246+
**10**'s `rightThread` to its `parent` **12**. What about **10**'s
247+
`leftThread`? Because we know that **10** < **12**, and **10** is the only
248+
`left` child of **12**, we can safely set **10**'s `leftThread` to **12**'s
249+
(now outdated) `leftThread`. Finally we set **12**'s `leftThread = nil`, as it
250+
now has a `left` child.
251+
252+
Let's now insert another node, **4**, into the tree:
238253

239254
![Insert2](Images/Insert2.png)
240255

241-
Insert3:
256+
While we are inserting **4** as a `right` child, it follows the exact same
257+
process as above, but mirrored (swap `left` and `right`). For the sake of
258+
completeness, we'll insert one final node, **15**:
242259

243260
![Insert3](Images/Insert3.png)
244261

245-
Remove1:
262+
Now that we have a fairly crowded tree, let's try removing some nodes.
263+
Compared to insertion, deletion is a little more complicated. Let's start with
264+
something simple, like removing **7**, which has no children:
246265

247266
![Remove1](Images/Remove1.png)
248267

249-
Remove2:
268+
Before we can just throw **7** away, we have to perform some clean-up. In this
269+
case, because **7** is a `right` child and has no children itself, we can
270+
simply set the `rightThread` of **7**'s `parent`(**5**) to **7**'s (now
271+
outdated) `rightThread`. Then we can just set **7**'s `parent`, `left`,
272+
`right`, `leftThread`, and `rightThread` to `nil`, effectively removing it from
273+
the tree.
274+
275+
Let's try something a little harder. Say we remove **5** from the tree:
250276

251277
![Remove2](Images/Remove2.png)
252278

253-
Remove3:
279+
This is a little trickier, as **5** has some children that we have to deal
280+
with. The core idea is to replace **5** with its first child, **2**. To
281+
accomplish this, we of course set **2**'s `parent` to **9** and set **9**'s
282+
`left` child to **2**. Note that **4**'s `rightThread` used to be **5**, but
283+
we are removing **5**, so it needs to change. It is now important to
284+
understand two important properties of threaded binary trees:
285+
286+
1. For the rightmost node **m** in the `left` subtree of any node **n**,
287+
**m**'s `rightThread` is **n**.
288+
2. For the leftmost node **m** in the `right` subtree of any node **n**,
289+
**m**'s `leftThread` is **n**.
290+
291+
Note how this property held true before the removal of **5**, as **4** was the
292+
rightmost node in **5**'s `left` subtree. In order to maintain this property,
293+
we must set **4**'s `rightThread` to **9**, as **4** is now the rightmost node
294+
in **9**'s `left` subtree. To completely remove **5**, all we now have to do
295+
is set **5**'s `parent`, `left`, `right`, `leftThread`, and `rightThread` to
296+
`nil`.
297+
298+
How about we do something crazy? What would happen if we tried to remove
299+
**9**, the root node? This is the resulting tree:
254300

255301
![Remove3](Images/Remove3.png)
256302

257-
Remove4:
303+
Whenever we want to remove a node that has two children, we take a slightly
304+
different approach than the above examples. The basic idea is to replace the
305+
node that we want to remove with the leftmost node in its `right` subtree,
306+
which we call the replacement node.
307+
308+
> Note: we could also replace the node with the rightmost node in its `left`
309+
> subtree. Choosing left or right is mostly an arbitrary decision.
310+
311+
Once we find the replacement node, **10** in this case, we remove it from the
312+
tree using the algorithms outlined above. This ensures that the edges in the
313+
`right` subtree remain correct. From there it is easy to replace **9** with
314+
**10**, as we just have to update the edges leaving **10**. Now all we have to
315+
do is fiddle with the threads in order to maintain the two properties outlined
316+
above. In this case, **12**'s `leftThread` is now **10**. Node **9** is no
317+
longer needed, so we can finish teh removal process by setting all of its
318+
variables to `nil`.
319+
320+
In order to illustrate how to remove a node that has only a `right` child,
321+
we'll remove one final node, **12** from the tree:
258322

259323
![Remove4](Images/Remove4.png)
260324

325+
The process to remove **12** is identical to the process we used to remove
326+
**5**, but mirrored. **5** had a `left` child, while **12** has a `right`
327+
child, but the core algorithm is the same.
328+
329+
That is a quick overview of how insertion and deletion work in threaded binary
330+
trees. More detail can of course be found in
331+
[the implementation](ThreadedBinaryTree.swift).
332+
261333

262334
## Miscellaneous methods
263335

@@ -271,7 +343,9 @@ find [further documentation here](../Binary Search Tree/).
271343

272344
## See also
273345

274-
[Threaded Binary Tree on Wikipedia](https://en.wikipedia.org/wiki/Threaded_binary_tree).
346+
[Threaded Binary Tree on Wikipedia](https://en.wikipedia.org/wiki/Threaded_binary_tree)
275347

276348
*Written for the Swift Algorithm Club by
277349
[Jayson Tung](https://github.com/JFTung)*
350+
351+
*Images made using www.draw.io*

0 commit comments

Comments
 (0)