From 6e16de2a37094041bb6aa9bb632c3bd60e4eaf24 Mon Sep 17 00:00:00 2001 From: NehaKeshan <39170739+NehaKeshan@users.noreply.github.com> Date: Tue, 26 Mar 2024 12:14:18 -0400 Subject: [PATCH] Update README.md updated the lecture flow and content. --- lectures/20_trees_III/README.md | 270 ++++++++++++++++---------------- 1 file changed, 135 insertions(+), 135 deletions(-) diff --git a/lectures/20_trees_III/README.md b/lectures/20_trees_III/README.md index 15502ae..f465a89 100644 --- a/lectures/20_trees_III/README.md +++ b/lectures/20_trees_III/README.md @@ -10,9 +10,9 @@ of pointers to the iterator. ## Today’s Lecture -- Last piece of ds_set: destrot, removing an item, erase - Breadth-first and depth-first tree search - Tree height, longest-shortest paths, breadth-first search +- Last piece of ds_set: removing an item, erase - Erase with parent pointers, increment operation on iterators - Limitations of our ds set implementation @@ -38,7 +38,140 @@ only one valid memory layout for this data as a ds set? Why?     -## 20.2 Erase +## 20.2 Depth-first vs. Breadth-first Search + +- We should also discuss two other important tree traversal terms related to problem solving and searching. + - In a depth-first search, we greedily follow links down into the tree, and don’t backtrack until we have hit a leaf. When we hit a leaf we step back out, but only to the last decision point and then proceed to the next leaf. This search method will quickly investigate leaf nodes, but if it has made an “incorrect” branch decision early in the search, it will take a long time to work back to that point and go down the “right” branch. + + - In a breadth-first search, the nodes are visited with priority based on their distance from the root, with nodes closer to the root visited first. In other words, we visit the nodes by level, first the root (level 0), then all children of the root (level 1), then all nodes 2 links from the root (level 2), etc. If there are multiple solution nodes, this search method will find the solution node with the shortest path to the root node. However, the breadth-first search method is memory-intensive, because the implementation must store all nodes at the current level – and the worst case number of nodes on each level doubles as we progress down the tree! + +- Both depth-first and breadth-first will eventually visit all elements in the tree. +- Note: The ordering of elements visited by depth-first and breadth-first is not fully specified. + - In-order, pre-order, and post-order are all examples of depth-first tree traversals. Note: A simple recursive tree function is usually a depth-first traversal. + + - What is a breadth-first traversal of the elements in our sample binary search trees above? + +## 20.3 General-Purpose Breadth-First Search/Tree Traversal + +- Write an algorithm to print the nodes in the tree one tier at a time, that is, in a breadth-first manner. + + ```cpp + BFS code discussed in class + + void breadth_first_traverse(Node* root) + { + int level=0; + std::vector current_level; + std::vector next_level; + if(root==NULL){return;} + current_level.push_back(root); + while(current_level.size()!=0) + { + std::cout<<"level"<left != NULL) + next_level.push_back(current_level[i]->left); + if(current_level[i]->right != NULL) + next_level.push_back(current_level[i]->right); + std::cout<<" "<value; + } + current_level = next_level; + level++; + next_level.clear(); + std::cout<right==NULL && p->left==NULL) + return 1; + + unsigned int left = 1 + height(p->left); + unsigned int right = 1 + height(p->right); + if (left>right) + return left + return right; +} +``` + +```cpp +another method of writing the above code + +unsigned int height(Node* p) +{ + if (p) return 0; + + return 1 + std::max(height(p->left), height(p->right)); +} +``` + +## 20.5 Shortest Paths to Leaf Node + +- Now let’s write a function to instead calculate the shortest path to a NULL child pointer. +  +  +  + +```cpp +code generated in class + +void shortest_path_breadth(Node* root) + { + unsigned int level=0; + std::vector current_level; + std::vector next_level; + if(root==NULL){return level;} + current_level.push_back(root); + while(current_level.size()!=0) + { + level++; + for (unsigned i=0; ileft != NULL) + next_level.push_back(current_level[i]->left); + else return level; + if(current_level[i]->right != NULL) + next_level.push_back(current_level[i]->right); + else return level; + } + } + current_level = next_level; + next_level.clear(); + } + } +``` + +- What is the running time of this algorithm? Can we do better? Hint: How does a breadth-first vs. depth-first algorithm for this problem compare? +  +  +  + +## 20.6 Erase - First we need to find the node to remove. Once it is found, the actual removal is easy if the node has no children or only one child. @@ -120,139 +253,6 @@ return 0; } ``` -## 20.3 Depth-first vs. Breadth-first Search - -- We should also discuss two other important tree traversal terms related to problem solving and searching. - - In a depth-first search, we greedily follow links down into the tree, and don’t backtrack until we have hit a leaf. When we hit a leaf we step back out, but only to the last decision point and then proceed to the next leaf. This search method will quickly investigate leaf nodes, but if it has made an “incorrect” branch decision early in the search, it will take a long time to work back to that point and go down the “right” branch. - - - In a breadth-first search, the nodes are visited with priority based on their distance from the root, with nodes closer to the root visited first. In other words, we visit the nodes by level, first the root (level 0), then all children of the root (level 1), then all nodes 2 links from the root (level 2), etc. If there are multiple solution nodes, this search method will find the solution node with the shortest path to the root node. However, the breadth-first search method is memory-intensive, because the implementation must store all nodes at the current level – and the worst case number of nodes on each level doubles as we progress down the tree! - -- Both depth-first and breadth-first will eventually visit all elements in the tree. -- Note: The ordering of elements visited by depth-first and breadth-first is not fully specified. - - In-order, pre-order, and post-order are all examples of depth-first tree traversals. Note: A simple recursive tree function is usually a depth-first traversal. - - - What is a breadth-first traversal of the elements in our sample binary search trees above? - -## 20.4 General-Purpose Breadth-First Search/Tree Traversal - -- Write an algorithm to print the nodes in the tree one tier at a time, that is, in a breadth-first manner. - - ```cpp - BFS code discussed in class - - void breadth_first_traverse(Node* root) - { - int level=0; - std::vector current_level; - std::vector next_level; - if(root==NULL){return;} - current_level.push_back(root); - while(current_level.size()!=0) - { - std::cout<<"level"<left != NULL) - next_level.push_back(current_level[i]->left); - if(current_level[i]->right != NULL) - next_level.push_back(current_level[i]->right); - std::cout<<" "<value; - } - current_level = next_level; - level++; - next_level.clear(); - std::cout<right==NULL && p->left==NULL) - return 1; - - unsigned int left = 1 + height(p->left); - unsigned int right = 1 + height(p->right); - if (left>right) - return left - return right; -} -``` - -```cpp -another method of writing the above code - -unsigned int height(Node* p) -{ - if (p) return 0; - - return 1 + std::max(height(p->left), height(p->right)); -} -``` - -## 20.6 Shortest Paths to Leaf Node - -- Now let’s write a function to instead calculate the shortest path to a NULL child pointer. -  -  -  - -```cpp -code generated in class - -void shortest_path_breadth(Node* root) - { - unsigned int level=0; - std::vector current_level; - std::vector next_level; - if(root==NULL){return level;} - current_level.push_back(root); - while(current_level.size()!=0) - { - level++; - for (unsigned i=0; ileft != NULL) - next_level.push_back(current_level[i]->left); - else return level; - if(current_level[i]->right != NULL) - next_level.push_back(current_level[i]->right); - else return level; - } - } - current_level = next_level; - next_level.clear(); - } - } -``` - -- What is the running time of this algorithm? Can we do better? Hint: How does a breadth-first vs. depth-first algorithm for this problem compare? -  -  -  - ## 20.7 Erase (now with parent pointers) - If we choose to use parent pointers, we need to add to the Node representation, and re-implement several ds_set member functions.