1 / 45

Understanding Binary Tree Traversals and Operations

Learn about binary tree traversals and operations including evaluating expressions, search trees, searching, inserting, deleting, and printing items. Dive into pre-order, in-order, post-order, and level-order traversals.

lauril
Download Presentation

Understanding Binary Tree Traversals and Operations

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Lecture #12 • Binary Tree Traversals • Using Binary Trees to Evaluate Expressions • Binary Search Trees • Binary Search Tree Operations • Searching for an item • Inserting a new item • Finding the minimum and maximum items • Printing out the items in order • Deleting the whole tree

  2. Binary Tree Traversals When we process all the nodes in a tree, it’s called a traversal. There are four common ways to traverse a tree. 1. Pre-order traversal (we did this last time) 2. In-order traversal 3. Post-order traversal 4. Level-order traversal Let’s see a pre-order traversal first!

  3. The In-order Traversal cur cur • Process the nodes in the left sub-tree. • Process the current node. • Process the nodes in the right sub-tree. root “a” “c” “b” NULL NULL NULL NULL void InOrder(Node *cur) { if (cur == NULL) // if empty, return… return; InOrder(cur->left); // Process nodes in left sub-tree. cout << cur->value; // Process the current node. InOrder(cur-> right); // Process nodes in left sub-tree. } void InOrder(Node *cur) { if (cur == NULL) // if empty, return… return; InOrder(cur->left); // Process nodes in left sub-tree. cout << cur->value; // Process the current node. InOrder(cur-> right); // Process nodes in left sub-tree. } Output: b

  4. The In-order Traversal cur cur • Process the nodes in the left sub-tree. • Process the current node. • Process the nodes in the right sub-tree. root “a” “c” “b” NULL NULL NULL NULL void InOrder(Node *cur) { if (cur == NULL) // if empty, return… return; InOrder(cur->left); // Process nodes in left sub-tree. cout << cur->value; // Process the current node. InOrder(cur-> right); // Process nodes in left sub-tree. } void InOrder(Node *cur) { if (cur == NULL) // if empty, return… return; InOrder(cur->left); // Process nodes in left sub-tree. cout << cur->value; // Process the current node. InOrder(cur-> right); // Process nodes in left sub-tree. } Output: b c a

  5. The Post-order Traversal cur cur • Process the nodes in the left sub-tree. • Process the nodes in the right sub-tree. • Process the current node. root “a” “c” “b” NULL NULL NULL NULL void PostOrder(Node *cur) { if (cur == NULL) // if empty, return… return; PostOrder(cur->left); // Process nodes in left sub-tree. PostOrder(cur-> right); // Process nodes in right sub-tree. cout << cur->value; // Process the current node. } void PostOrder(Node *cur) { if (cur == NULL) // if empty, return… return; PostOrder(cur->left); // Process nodes in left sub-tree. PostOrder(cur-> right); // Process nodes in right sub-tree. cout << cur->value; // Process the current node. } Output: b

  6. The Post-order Traversal cur cur • Process the nodes in the left sub-tree. • Process the nodes in the right sub-tree. • Process the current node. root “a” “c” “b” NULL NULL NULL NULL void PostOrder(Node *cur) { if (cur == NULL) // if empty, return… return; PostOrder(cur->left); // Process nodes in left sub-tree. PostOrder(cur-> right); // Process nodes in right sub-tree. cout << cur->value; // Process the current node. } void PostOrder(Node *cur) { if (cur == NULL) // if empty, return… return; PostOrder(cur->left); // Process nodes in left sub-tree. PostOrder(cur-> right); // Process nodes in right sub-tree. cout << cur->value; // Process the current node. } Output: b a c

  7. The Level Order Traversal 900 760 800 780 720 temp front rear In a level order traversal we visit each level’s nodes, from left to right, before visiting nodes in the next level. 700 720 800 780 Here’s the algorithm: 700 700 • Use a temp pointer variable and a queue of node pointers. • Insert the root node pointer into the queue. • While the queue is not empty: • Dequeue the top node pointer and put it in temp. • Process the node. • Add the node’s children to queue if they are not NULL. root “a” 720 780 “c” “b” NULL 900 760 800 “f” “e” “d” NULL NULL NULL NULL NULL NULL 780 700 780 720 900 800 760 900 760 800 760 a b c d Etc…

  8. Traversal Overview, Part 1 root root “a” “a” “b” “b” “c” “c” NULL NULL NULL NULL “e” “e” “d” “d” NULL NULL NULL NULL NULL NULL NULL NULL Pre-order In-order #17 #17 #18 #15 #19 #16 #15 #13 #19 #14 #12 #14 #10 #12 #16 #13 #10 #18 #11 #11 #7 #6 #8 #3 #8 #9 #2 #3 #5 #9 #5 #6 #4 #2 #7 #4 #1 #1 1. Process current node 2. Traverse left 3. Traverse right 1. Traverse left 2. Process current node 3. Traverse right

  9. Traversal Overview, Part 2 root root “a” “a” “b” “b” “c” “c” NULL NULL NULL NULL “e” “e” “d” “d” NULL NULL NULL NULL NULL NULL NULL NULL Post-order Level-order #15 #17 #12 #14 #18 #10 #19 #13 #16 #11 #6 #5 #4 #7 #5 #2 #2 #8 #3 #3 #4 #9 #1 #1 1. Traverse left 2. Traverse right 3. Process current node

  10. Big-Oh of Traversals? Question: What’re the big-ohs of each of our traversals? Answer: Well, since a traversal must visit each node exactly once… and since there are n nodes in a tree… the big-oh for any of the traversals is… O(n)

  11. Traversal Challenge root “Larry” “Ronda” “Fran” NULL “Danny” “Jack” “Tom” NULL NULL NULL NULL NULL “Sam” NULL NULL Challenge: What order will the following nodes be printed out if we use an in-order traversal? RULES • The class will split into left and right teams • One student from each team will come up to the board • Each student can either • write one new item or • fix a single error in their teammates solution • Then the next two people come up, etc. • The team that completes their program first wins!

  12. Expression Evaluation We can represent arithmetic expressions using a binary tree. For example, the tree on the left represents the expression: (5+6)*(3-1) ptr Once you have an expression in a tree, its easy to evaluate it and get the result. Let’s see how!

  13. Expression Evaluation cur cur cur Here’s our evaluation function. We start by passing in a pointer to the root of the tree. (5+6)*(3-1) • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. ptr

  14. Expression Evaluation cur cur cur Here’s our evaluation function. We start by passing in a pointer to the root of the tree. (5+6)*(3-1) • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. ptr Result = 5

  15. Expression Evaluation cur cur Here’s our evaluation function. We start by passing in a pointer to the root of the tree. (5+6)*(3-1) • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. ptr Result = 5 Result = 6 5+6 = 11

  16. Expression Evaluation cur cur Here’s our evaluation function. We start by passing in a pointer to the root of the tree. (5+6)*(3-1) • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. ptr Result = 3 Result = 11 Result = 1 3-1 = 2

  17. Expression Evaluation cur Here’s our evaluation function. We start by passing in a pointer to the root of the tree. The result is 22. (5+6)*(3-1) • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. ptr Result = 11 Result = 2 11*2=22 3-1 = 2

  18. Expression Evaluation Here’s our evaluation function. We start by passing in a pointer to the root of the tree. • If the current node is a number, return its value. • Recursivelyevaluate the left subtree and get the result. • Recursively evaluate the right subtree and get the result. • Apply the operator in the current node to the left and right results; return the result. Question: Which other algorithm does this remind you of?

  19. Binary Search Trees root “Larry” “Ronda” “Fran” NULL “Danny” “Jack” “Tom” NULL NULL NULL NULL NULL “Sam” NULL NULL Binary Search Trees are a type of binary tree with specific properties that make them very efficient to search for a value in the tree. Like regular Binary Trees, we store and search for values in Binary Search Trees… Here’s an example BST…

  20. Binary Search Trees root “Larry” “Ronda” “Fran” NULL “Danny” “Jack” “Tom” NULL NULL NULL NULL NULL “Sam” NULL NULL BST Definition: A Binary Search Tree is a binary tree with the following two properties: Given any node in the binary tree, all nodes in its left sub-tree must be less than the node’s value. Given any node in the binary tree, all nodes in its right sub-tree must be greater than the node’s value. Let’s validate that thisis a valid BST…

  21. Binary Search Trees Question: Which of the following are valid BSTs? “Larry” “Larry” NULL “Fran” “Ronda” “Fran” NULL NULL NULL “Danny” “Manny” “Danny” “Nick” NULL NULL NULL NULL NULL “Alex” “Nick” “Amy” NULL NULL NULL NULL NULL “Maddy” NULL NULL

  22. Operations on a Binary Search Tree Here’s what we can do to a BST: • Determine if the binary search tree is empty • Search the binary search tree for a value • Insert an item in the binary search tree • Delete an item from the binary search tree • Find the height of the binary search tree • Find the number of nodes and leaves in the binary search tree • Traverse the binary search tree • Free the memory used by the binary search tree

  23. Searching a BST Input: A value V to search for Output: TRUE if found, FALSE otherwise Start at the root of the tree Keep going until we hit the NULL pointer If V is equal to current node’s value, then found! If V is less than current node’s value, go left If V is greater than current node’s value, go right If we hit a NULL pointer, not found. “Larry” Gary == Larry?? Gary < Fran?? Gary == Fran?? Gary < Larry?? Gary > Fran?? Gary == Gary?? “Ronda” “Fran” NULL NULL Let’s search for Gary. “Barry” “Gary” NULL NULL NULL NULL

  24. Searching a BST Start at the root of the tree Keep going until we hit the NULL pointer If V is equal to current node’s value, then found! If V is less than current node’s value, go left If V is greater than current node’s value, go right If we hit a NULL pointer, not found. • Show how to search for: • Khang • Dale • Sam

  25. Searching a BST Here are two different BST search algorithms in C++, one recursive and one iterative: bool Search(int V,Node *ptr) {   while (ptr != NULL) {  if (V == ptr->value)       return(true); else if (V < ptr->value)     ptr = ptr->left; else     ptr = ptr->right; }  return(false); // nope } bool Search(int V, Node *ptr) {   if (ptr == NULL)     return(false); // nope else if (V == ptr->value)     return(true); // found!!!   else if (V < ptr->value)     return(Search(V,ptr->left));  else     return(Search(V,ptr->right)); } Let’s trace through the recursive version…

  26. Recursive BST Search true Lets search for 14. pRoot ptr-> 13 14 == 13?? 14 == 14?? 14 < 17?? 14 == 17?? 14 < 13?? bool Search(int V, Node *ptr) {   if (ptr == NULL)     return(false); // nope else if (V == ptr->value)     return(true); // found!!!   else if (V < ptr->value)     return(Search(V,ptr->left));  else     return(Search(V,ptr->right)); } bool Search(int V, Node *ptr) {   if (ptr == NULL)     return(false); // nope else if (V == ptr->value)     return(true); // found!!!   else if (V < ptr->value)     return(Search(V,ptr->left));  else     return(Search(V,ptr->right)); } ptr-> 17 7 bool Search(int V, Node *ptr) {   if (ptr == NULL)     return(false); // nope else if (V == ptr->value)     return(true); // found!!!   else if (V < ptr->value)     return(Search(V,ptr->left));  else     return(Search(V,ptr->right)); } NULL ptr-> 3 19 14 NULL NULL NULL NULL NULL NULL void main(void) { bool bFnd; bFnd = Search(14,pRoot);}

  27. Recursive BST Search true true true Lets search for 14. pRoot ptr-> 13 bool Search(int V, Node *ptr) {   if (ptr == NULL)     return(false); // nope else if (V == ptr->value)     return(true); // found!!!   else if (V < ptr->value)     return(Search(V,ptr->left));  else     return(Search(V,ptr->right)); } ptr-> 17 7 bool Search(int V, Node *ptr) {   if (ptr == NULL)     return(false); // nope else if (V == ptr->value)     return(true); // found!!!   else if (V < ptr->value)     return(Search(V,ptr->left));  else     return(Search(V,ptr->right)); } NULL 3 19 14 NULL NULL NULL NULL NULL NULL void main(void) { bool bFnd; bFnd = Search(14,pRoot);}

  28. Recursive BST Search true true true true true Lets search for 14. pRoot ptr-> 13 17 7 bool Search(int V, Node *ptr) {   if (ptr == NULL)     return(false); // nope else if (V == ptr->value)     return(true); // found!!!   else if (V < ptr->value)     return(Search(V,ptr->left));  else     return(Search(V,ptr->right)); } NULL 3 19 14 NULL NULL NULL NULL NULL NULL int main(void) {boolbFnd;bFnd = Search(14,pRoot);}

  29. Big Oh of BST Search Question: In the average BST with N values, how many steps are required to find our value? 50% eliminated! 50% eliminated! 50% eliminated! Right! log2(N) steps 50% eliminated! Question: In the worst case BST with N values, how many steps are required find our value? Right! N steps Question: If there are 4 billion nodes in a BST, how many steps will it take to perform a search? WOW! Now that’s PIMP! Just 32!

  30. Inserting A New Value Into A BST Carly Alice Ken To insert a new node in our BST, we must place the new node so that the resulting tree is still a valid BST! Where would the following new values go? Carly Ken Alice

  31. Inserting A New Value Into A BST Input: A value Vto insert If the tree is empty Allocate a new node and put V into it Point the root pointer to our new node. DONE! Start at the root of the tree While we’re not done… If V is equal to current node’s value, DONE! (nothing to do...) If V is less than current node’s value If there is a left child, then go left ELSE allocate a new node and put V into it, and set current node’s left pointer to new node. DONE! If V is greater than current node’s value If there is a right child, then go right ELSE allocate a new node and put V into it, set current node’s right pointer to new node. DONE!

  32. Now the C++ Code! And here’s our Binary Search Tree class. void insert(const std::string &value) { if (m_root == NULL) { m_root = new Node(value); return; } Node *cur = m_root; for (;;) { if (value == cur->value) return; if (value < cur->value) { if (cur->left != NULL) cur = cur->left; else { cur->left = new Node(value); return; } } else if (value > cur->value) { if (cur->right != NULL) cur = cur->right; else { cur->right = new Node(value); return; } } } } Just as with a regular binary tree, we use a node struct to hold our items. However let’s add a constructor to our Node so we can easily create a new one! If our tree is empty, allocate a new node and point the root pointer to it – then we’re done! class BinarySearchTree { public: BinarySearchTree() { m_root = NULL; } void insert(const std::string &value) { … } private: Node *m_root; }; Start traversing down from the root of the tree. for(;;) is the same as an infinite loop. struct Node { std::string value; Node *left,*right; }; And our constructor initializes that root pointer to NULLwhen we create a new tree. (This indicates the tree is empty) If our value is already in the tree, then we’re done - just return. Node(const std::string &myVal) { value = myVal; left = right = NULL; } If the value to insert is less than the current node’s value, then go left. If there is a node to our left, advance to that node and continue. Now let’s see our complete insertion function in C++. Otherwise we’ve found the proper spot for our new value! Add our value as the left child of the current node. If the value we want to insert is greater than the current node’s value, then traverse/insert to the right. Our BST class has a single member variable – the root pointer to the tree.

  33. void insert(const std::string &value) { if (m_root == NULL) { m_root = new Node(value); return; } Node *cur = m_root; for (;;) { if (value == cur->value) return; if (value < cur->value) { if (cur->left != NULL) cur = cur->left; else { cur->left = new Node(value); return; } } else if (value > cur->value) { if (cur->right != NULL) cur = cur->right; else { cur->right = new Node(value); return; } } } } m_root NULL “Larry” NULL NULL void main(void){ BinarySearchTree bst; bst.insert(“Larry”); ... bst.insert(“Phil”);}

  34. void insert(const std::string &value) { if (m_root == NULL) { m_root = new Node(value); return; } Node *cur = m_root; for (;;) { if (value == cur->value) return; if (value < cur->value) { if (cur->left != NULL) cur = cur->left; else { cur->left = new Node(value); return; } } else if (value > cur->value) { if (cur->right != NULL) cur = cur->right; else { cur->right = new Node(value); return; } } } } m_root cur “Larry” Phil == Larry?? Phil == Ronda?? ? Phil < Larry?? Phil < Ronda?? “Ronda” “Fran” NULL NULL ? “Phil” “Barry” NULL NULL NULL NULL Phil > Larry?? void main(void){ BinarySearchTree bst; bst.insert(“Larry”); ... bst.insert(“Phil”);}

  35. Inserting A New Value Into A BST As with BST Search, there is a recursive version of the Insertion algorithm too. Be familiar with it! Question: Given a random array of numbers if you insert them one at a time into a BST, what will the BST look like? Question: Given a ordered array of numbers if you insert them one at a time into a BST, what will the BST look like?

  36. Big Oh of BST Insertion So, what’s the big-oh of BST Insertion? Right! It’s also O(log2n) Why? Because we have to first use a binary search to find where to insert our node and binary search is O(log2n). Once we’ve found the right spot, we can insert our new node in O(1) time. Groovy Baby!

  37. Finding Min & Max of a BST “Larry” “Ronda” “Fran” NULL NULL “Phil” “Barry” NULL NULL NULL NULL How do we find the minimum and maximum values in a BST? The minimum value is located at the left-most node. The maximum value is located at the right-most node. int GetMin(node *pRoot) { if (pRoot == NULL) return(-1); // empty while (pRoot->left != NULL) pRoot = pRoot->left; return(pRoot->value); } int GetMax(node *pRoot) { if (pRoot == NULL) return(-1); // empty while (pRoot->right != NULL) pRoot = pRoot->right; return(pRoot->value); } Question: What’s the big-oh to find the minimum or maximum element?

  38. Finding Min & Max of a BST And here are recursive versions for you… int GetMin(node *pRoot) { if (pRoot == NULL) return(-1); // empty if (pRoot->left == NULL) return(pRoot->value); return(GetMin(pRoot->left)); } int GetMax(node *pRoot) { if (pRoot == NULL) return(-1); // empty if (pRoot->right == NULL) return(pRoot->value); return(GetMax(pRoot->right)); } Hopefully you’re getting the idea that most tree functions can be done recursively…

  39. Printing a BST In Alphabetical Order cur root “jane” cur cur cur cur cur cur cur cur “waa” “danny” NULL NULL “frank” “bill” NULL NULL NULL NULL Can anyone guess what algorithm we use to print out a BST in alphabetical order? void InOrder(Node *cur) { if (cur == NULL) // if empty, return… return; InOrder(cur->left); // Process nodes in left sub-tree. cout << cur->value; // Process the current node. InOrder(cur-> right); // Process nodes in left sub-tree. } Big-oh Alert! So what’s the big-Oh of printingall the items in the tree? Output: bill danny frank Right! O(n) since we have to visit and print all n items. jane waa

  40. Freeing The Whole Tree When we are done with our BST, we have to free every node in the tree, one at a time. Question: Can anyone think of an algorithm for this? void FreeTree(Node *cur) { if (cur == NULL) // if empty, return… return; FreeTree(cur->left); // Delete nodes in left sub-tree. FreeTree (cur-> right); // Delete nodes in left sub-tree. delete cur; // Free the current node }

  41. Freeing The Whole Tree cur-> “Larry” cur-> “Ronda” “Fran” cur= NULL NULL NULL void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } cur-> “Gabby” “Barry” void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } NULL NULL NULL NULL void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; }

  42. Freeing The Whole Tree cur-> “Larry” cur-> “Ronda” “Fran” NULL NULL cur-> “Gabby” “Barry” void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } NULL NULL NULL NULL void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; }

  43. Freeing The Whole Tree cur-> “Larry” cur-> “Ronda” “Fran” NULL NULL cur-> “Gabby” void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } NULL NULL void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; }

  44. Freeing The Whole Tree cur-> “Larry” cur-> “Ronda” “Fran” NULL NULL void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } void FreeTree(Node *cur) { if (cur == NULL) return; FreeTree(cur->left); FreeTree (cur-> right); delete cur; } Big-oh Alert! So what’s the big-Oh of freeingall the items in the tree? And so on… It’s still O(n) since we have to visit all n items.

  45. Appendix Slides

More Related