2
2
3
3
A threaded binary tree is a special kind of [ binary tree] (../Binary Tree/) (a
4
4
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.
6
9
7
10
If you don't know what a tree is or what it is for, then
8
11
[ read this first] ( ../Tree/ ) .
@@ -11,14 +14,15 @@ If you don't know what a tree is or what it is for, then
11
14
## In-order traversal
12
15
13
16
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
15
18
of the tree. An in-order traversal of a binary tree visits the nodes in the
16
19
order in which they are stored, which matches the underlying ordering of a
17
20
[ binary search tree] (../Binary Search Tree/). The idea is to visit all the
18
21
left children of a node first, then visit the node itself, and visit the left
19
22
children last.
20
23
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):
22
26
23
27
``` swift
24
28
func traverse (n : Node? ) {
@@ -48,15 +52,15 @@ A threaded binary tree fixes this problem.
48
52
## Predecessors and successors
49
53
50
54
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
54
58
stores the node's predecessor (if it exists), and each right child that would
55
59
normally be ` nil ` instead stores the node's successor (if it exists). This is
56
60
what separates threaded binary trees from standard binary trees.
57
61
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** :
60
64
- A single threaded tree keeps track of ** either** the in-order predecessor
61
65
** or** successor (left ** or** right).
62
66
- A double threaded tree keeps track of ** both** the in-order predecessor
@@ -110,17 +114,18 @@ Swift *optionals*.
110
114
- ` leftThread: ThreadedBinaryTree? ` is the in-order predecessor of this node
111
115
- ` rightThread: ThreadedBinaryTree? ` is the in-order successor of this node
112
116
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
114
119
` ThreadedBinaryTree ` class.
115
120
116
121
117
122
## Traversal algorithm
118
123
119
124
Let's start with the main reason we're using a threaded binary tree. It is now
120
125
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.
124
129
125
130
``` swift
126
131
func predecessor () -> ThreadedBinaryTree<T>? {
@@ -227,37 +232,104 @@ Let's start with the same tree that we used for the above traversal example:
227
232
228
233
![ Base] ( Images/Base.png )
229
234
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
231
236
this, with the changes highlighted in red:
232
237
233
238
![ Insert1] ( Images/Insert1.png )
234
239
235
240
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:
238
253
239
254
![ Insert2] ( Images/Insert2.png )
240
255
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** :
242
259
243
260
![ Insert3] ( Images/Insert3.png )
244
261
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:
246
265
247
266
![ Remove1] ( Images/Remove1.png )
248
267
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:
250
276
251
277
![ Remove2] ( Images/Remove2.png )
252
278
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:
254
300
255
301
![ Remove3] ( Images/Remove3.png )
256
302
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:
258
322
259
323
![ Remove4] ( Images/Remove4.png )
260
324
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
+
261
333
262
334
## Miscellaneous methods
263
335
@@ -271,7 +343,9 @@ find [further documentation here](../Binary Search Tree/).
271
343
272
344
## See also
273
345
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 )
275
347
276
348
* Written for the Swift Algorithm Club by
277
349
[ Jayson Tung] ( https://github.com/JFTung ) *
350
+
351
+ * Images made using www.draw.io *
0 commit comments