1 Chapter 10 Trees
2 Definition of Tree A tree is a set of linked nodes, such that there is one and only one path from a unique node (called the root node) to every other node in the tree. A path exists from node A to node B if one can follow a chain of pointers to travel from node A to node B.
3 A E F B C D G A set of linked nodes Paths There is one path from A to B There is a path from D to B There is also a second path from D to B.
4 A E F B C D G There is no path from C to any other node. Paths (cont.)
5 Cycles There is no cycle (circle of pointers) in a tree. Any linked structure that has a cycle would have more than one path from the root node to another node.
6 Example of a Cycle A C D B E C → D → B → E → C
7 Tree Cannot Have a Cycle A C D B E 2 paths exist from A to C: 1. A → C 2. A → C → D → B → E → C
8 Example of a Tree A C B D E F G root In a tree, every pair of linked nodes have a parent-child relationship (the parent is closer to the root)
9 Example of a Tree (cont.) A C B D E F G root For example, C is a parent of G
10 Example of a Tree (cont.) A C B D E F G root E and F are children of D
11 Example of a Tree (cont.) A C B D E F G root The root node is the only node that has no parent.
12 Example of a Tree (cont.) A C B D E F G root Leaf nodes (or leaves for short) have no children.
13 Subtrees A B C I K D E F J G H subtree root A subtree is a part of a tree that is a tree in itself
14 Binary Trees A binary tree is a tree in which each node can only have up to two children…
15 NOT a Binary Tree A B C I K D E F J G H root C has 3 child nodes.
16 Example of a Binary Tree A B C I K E J G H root The links in a tree are often called edges
17 Levels A B C I K E J G H root level 0 level 1 level 2 level 3 The level of a node is the number of edges in the path from the root node to this node
18 Full Binary Tree B D H root I A E J K C F L M G N O In a full binary tree, each node has two children except for the nodes on the last level, which are leaf nodes
19 Complete Binary Trees A complete binary tree is a binary tree that is either –a full binary tree –OR –a tree that would be a full binary tree but it is missing the rightmost nodes on the last level
20 NOT a Complete Binary Trees B D H root A E C F G I Missing non-rightmost nodes on the last level
21 Complete Binary Trees (cont.) B D H root I A E J K C F L G Missing rightmost nodes on the last level
22 Complete Binary Trees (cont.) B D H root I A E J K C F L M G N O A full binary tree is also a complete binary tree.
23 Binary Search Trees A binary search tree is a binary tree that allows us to search for values that can be anywhere in the tree. Usually, we search for a certain key value, and once we find the node that contains it, we retrieve the rest of the info at that node. Therefore, we assume that all values searched for in a binary search tree are distinct.
24 Properties of Binary Search Trees A binary search tree does not have to be a complete binary tree. For any particular node, –the key in its left child (if any) is less than its key. –the key in its right child (if any) is greater than or equal to its key. Left < Parent <= Right.
25 Binary Search Tree (BST) Node template BSTNode { T info; BSTNode *left; BSTNode *right; }; The implementation of a binary search tree usually just maintains a single pointer in the private section called root, to point to the root node.
26 Inserting Nodes Into a BST 37, 2, 45, 48, 41, 29, 20, 30, 49, 7 Objects that need to be inserted (only key values are shown): root: NULL BST starts off empty
27 Inserting Nodes Into a BST (cont.) 37, 2, 45, 48, 41, 29, 20, 30, 49, 7 root 37
28 Inserting Nodes Into a BST (cont.) 2, 45, 48, 41, 29, 20, 30, 49, 7 root 37 2 < 37, so insert 2 on the left side of 37
29 Inserting Nodes Into a BST (cont.) 2, 45, 48, 41, 29, 20, 30, 49, 7 root 37 2
30 Inserting Nodes Into a BST (cont.) 45, 48, 41, 29, 20, 30, 49, 7 root > 37, so insert it at the right of 37
31 Inserting Nodes Into a BST (cont.) 45, 48, 41, 29, 20, 30, 49, 7 root
32 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root When comparing, we always start at the root node 48 > 37, so look to the right
33 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root This time, there is a node already to the right of the root node. We then compare 48 to this node 48 > 45, and 45 has no right child, so we insert 48 on the right of 45
34 Inserting Nodes Into a BST (cont.) 48, 41, 29, 20, 30, 49, 7 root
35 Inserting Nodes Into a BST (cont.) 41, 29, 20, 30, 49, 7 root > 37, so look to the right 41 < 45, so look to the left – there is no left child, so insert
36 Inserting Nodes Into a BST (cont.) 41, 29, 20, 30, 49, 7 root
37 Inserting Nodes Into a BST (cont.) 29, 20, 30, 49, 7 root < 37, left 29 > 2, right
38 Inserting Nodes Into a BST (cont.) 29, 20, 30, 49, 7 root
39 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root < 37, left 20 > 2, right 20 < 29, left
40 Inserting Nodes Into a BST (cont.) 20, 30, 49, 7 root
41 Inserting Nodes Into a BST (cont.) 30, 49, 7 root < > 2 30 > 29
42 Inserting Nodes Into a BST (cont.) 30, 49, 7 root
43 Inserting Nodes Into a BST (cont.) 49, 7 root > > > 48
44 Inserting Nodes Into a BST (cont.) 49, 7 root
45 Inserting Nodes Into a BST (cont.) 7 root < 37 7 > 2 7 < 29 7 < 20
46 Inserting Nodes Into a BST (cont.) 7 root
47 Inserting Nodes Into a BST (cont.) root All elements have been inserted 7
48 Searching for a Key in a BST root Searching for a key in a BST uses the same logic 7 Key to search for: 29
49 Searching for a Key in a BST (cont.) root Key to search for: < 37 7
50 Searching for a Key in a BST (cont.) root Key to search for: > 2 7
51 Searching for a Key in a BST (cont.) root Key to search for: == 29 FOUND IT! 7
52 Searching for a Key in a BST (cont.) root Key to search for: 3 7
53 Searching for a Key in a BST (cont.) root Key to search for: 3 3 < < 20 3 < 29 3 > 2 3 < 37
54 Searching for a Key in a BST (cont.) root Key to search for: 3 When the child pointer you want to follow is set to NULL, the key you are looking for is not in the BST 7
55 Searching a BST is Quicker than Array or Linked List root Search for a key in this BST takes max 5 comparisons (key = 7) 7
56 Searching a BST is Quicker than Array or Linked List (cont.) 37, 2, 45, 48, 41, 29, 20, 30, 49, 7 Searching for a key in linear data structures, such as array or linked list, takes max 10 comparisons (key = 7). In fact searching for key 29, 20, 30, 49, and 7 all takes more than 5 comparisons. Overall slower than BST. The main advantage of BST over linear data structures is quicker search.
57 Deleting a BST Node Deleting a node in a BST is a little tricky – it has to be deleted so that the resulting structure is still a BST with each node greater than its left child and less than its right child. Deleting a node is handled differently depending on whether the node: –has no children –has one child –has two children
58 Deletion Case 1: No Children root Node 49 has no children – to delete it, we just remove it
59 Deletion Case 1: No Children (cont.) root
60 Deletion Case 2: One Child root Node 48 has one child – to delete it, we just splice it out
61 Deletion Case 2: One Child (cont.) root Node 48 has one child – to delete it, we just splice it out
62 Deletion Case 2: One Child (cont.) root
63 Deletion Case 2: One Child (cont.) root Another example: node 2 has one child – to delete it we also splice it out
64 Deletion Case 2: One Child (cont.) root Another example: node 2 has one child – to delete it we also splice it out
65 Deletion Case 2: One Child (cont.) root
66 Deletion Case 3: Two Children root Node 37 has two children…
67 Deletion Case 3: Two Children (cont.) root to delete it, first we find the greatest node in its left subtree
68 Deletion Case 3: Two Children (cont.) root First, we go to the left once, then follow the right pointers as far as we can
69 Deletion Case 3: Two Children (cont.) root is the greatest node in the left subtree of node 37
70 Deletion Case 3: Two Children (cont.) root Next, we copy the object at node 30 into node 37
71 Deletion Case 3: Two Children (cont.) root Finally, we delete the lower red node using case 1 or case 2 deletion
72 Deletion Case 3: Two Children (cont.) root Let’s delete node 30 now
73 Deletion Case 3: Two Children (cont.) root is the greatest node in the left subtree of node 30
74 Deletion Case 3: Two Children (cont.) root Copy the object at node 29 into node 30
75 Deletion Case 3: Two Children (cont.) root This time, the lower red node has a child – to delete it we use case 2 deletion
76 Deletion Case 3: Two Children (cont.) root This time, the lower red node has a child – to delete it we use case 2 deletion
77 Deletion Case 3: Two Children (cont.) root
78 Searching a BST is Quicker than Array or Linked List root Search for a key in this BST takes max 5 comparisons (key = 7) 7
: Traversing a BST There are 3 ways to traversal a BST (visit every node in BST): –1. Preorder (parent → left → right) –2. Inorder (left → parent → right) –3. Postorder (left → right → parent) Result of traversing BST (at pp. 55): –Preorder: –Inorder: –Postorder:
80 1 template 2 class BinarySearchTree { 3 BSTNode *root; 4 void preOrderInternal (BST *parent) { … } 5 void inOrderInternal (BST *parent) { … } 6 void postOrderInternal (BST *parent) { … } 7 void insertInternal (BST *parent, 8 T& newElement) { … } 9 bool searchInternal (BST *parent, T& target, 10 T& foundElement) { … } Binary Search Tree Class Template
81 11 public: 12 BinarySearchTree() { … } 13 ~BinarySearchTree() { … } 14 bool isEmpty() { … } 15 void preOrderTraversal() { … } 16 void inOrderTraversal() { … } 17 void postOrderTraversal() { … } 18 void insert (T element) { … } 19 bool search (T element, T& foundElement) { … } 20 void makeEmpty() { … } 21 } Binary Search Tree Class Template (cont.)
82 1 BinarySearchTree() 2 : root(NULL) { } 3 4 ~BinarySearchTree() 5 { 6 makeEmpty(); 7 } 8 9 bool isEmpty() 10 { 11 return root == NULL: 12 } Constructor, Destructor, IsEmpty()
83 2 void inOrderTraversal() 3 { 4inOrderInternal (root); 5 } The client uses the driver called InOrderTraversal. Printing Elements In Order The recursive function inOrderInternal is called. inOrderInternal prints all element in BST in sorted order, starting from root node.
84 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } The base case occurs when parent is NULL – just returns. Printing Elements In Order (cont.)
85 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } There are 2 recursive calls under the if – the first advances the pointer to the left child… and the second advances the pointer to the right child. Printing Elements In Order (cont.)
86 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } Each recursive call approaches the base case… it goes down one level through the tree, and it get closer to the case where parent->left or parent->right is NULL. Printing Elements In Order (cont.)
87 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } If the BST contains only one node, the root node is the only node – the left and right pointers of the root node will be set to NULL. Printing Elements In Order (cont.)
88 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } parent->left is NULL, so NULL is passed into parent of the new inOrderInternal function. Printing Elements In Order (cont.)
89 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } Since parent is NULL in the new inOrderInternal function, it will return right away. Printing Elements In Order (cont.)
90 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } parent->right is NULL – thus, the recursive function call immediately returns as before. Printing Elements In Order (cont.)
91 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } Printing Elements In Order (cont.) In fact inOrderInternal works correctly when there is only 0, 1 or many node in the BST.
92 2 void inOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 inOrderInternal (parent->left); 6 cout info << " "; 7 inOrderInternal (parent->right); 8 } 9 } Printing Elements In Order (cont.) inOrderInternal is called once from the driver inOrderTraversal. Then, for each node in the tree, 2 calls to inOrderInternal are made, giving us a total of 2n + 1 calls where n is the number of nodes.
93 2 void preOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 cout info << " "; 6 preOrderInternal (parent->left); 7 preOrderInternal (parent->right); 8 } 9 } Printing Elements Pre Order preOrderInternal prints the parent first.
94 2 void postOrderInternal (BSTNode *parent) 3 { 4 if (parent != NULL) { 5 postOrderInternal (parent->left); 6 postOrderInternal (parent->right); 7 cout info << " "; 8 } 9 } Printing Elements Post Order postOrderInternal prints the parent last.
95 1 bool search (T target, T& foundElement) { 2 return searchInternal (root, target, foundElement); 3 } 4 5 void insert ( T& newElement) { 6 insertInternal (root, newElement); 7 } Searching and Insertion in BST
96 Searching and Insertion in BST We can actually figure out searchInternal and insertInternal using the same recursive logic as traversal in BST.
References Childs, J. S. (2008). Trees. C++ Classes and Data Structures. Prentice Hall. 97