From 09817c373618d13a344c10ce7516c3e95e14d4fd Mon Sep 17 00:00:00 2001 From: Jidong Xiao Date: Thu, 20 Mar 2025 23:34:12 -0400 Subject: [PATCH] adding general tree code --- lectures/19_trees_II/README.md | 92 ++++++++++++++++++- .../19_trees_II/general_tree_post_order.cpp | 79 ++++++++++++++++ .../19_trees_II/general_tree_pre_order.cpp | 74 +++++++++++++++ 3 files changed, 243 insertions(+), 2 deletions(-) create mode 100644 lectures/19_trees_II/general_tree_post_order.cpp create mode 100644 lectures/19_trees_II/general_tree_pre_order.cpp diff --git a/lectures/19_trees_II/README.md b/lectures/19_trees_II/README.md index ba3bc26..5248835 100644 --- a/lectures/19_trees_II/README.md +++ b/lectures/19_trees_II/README.md @@ -10,7 +10,6 @@ ## Today’s Lecture - Warmup / Review: destroy_tree -- A very important ds set operation insert - In-order, pre-order, and post-order traversal - Finding the in-order successor of a binary tree node, tree iterator increment @@ -113,7 +112,7 @@ Exercise: What are the advantages & disadvantages of each method? - The efficiency of the main insert, find and erase algorithms depends on the height of the tree. - The best-case and average-case heights of a binary search tree storing n nodes are both O(log n). The worstcase, which often can happen in practice, is O(n). - Developing more sophisticated algorithms to avoid the worst-case behavior will be covered in Introduction to -Algorithms. One elegant extension to the binary search tree is described below... +Algorithms. + +## 19.6 N-ary tree and General Tree + +- A tree where each node can have many children (not limited to two) is generally called an n-ary tree, where n refers to the maximum number of children each node can have. + +- If there is no fixed limit on the number of children, it's often simply referred to as a general tree or multi-way tree. + +- We can define the tree nodes for a general tree like this: + +```cpp +class Node { +public: + int val; + std::vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, std::vector _children) { + val = _val; + children = _children; + } +}; +``` + +## 19.7 General Tree Pre-order Traversal + +The following code implements the pre-order traversal of a general tree. + +```cpp +// make a helper function, since the original one doesn't take the vector as a parameter. +void preorder(Node* root, std::vector& result){ + if(root == NULL){ + return; + } + // visit the parent + result.push_back(root->val); + + int size = root->children.size(); + for(int i=0; ichildren[i], result); + } +} + +std::vector preorder(Node* root) { + std::vector result; + preorder(root, result); + return result; +} +``` + +You can run [this program](general_tree_pre_order.cpp) to test the above functions. + +## 19.8 General Tree Post-order Traversal + +The following code implements the post-order traversal of a general tree. + +```cpp +// make a helper function, since the original one doesn't take the vector as a parameter. +void postorder(Node* root, std::vector& result){ + // base case + if(root==NULL){ + return; + } + + // children first + int size = (root->children).size(); + for(int i=0; ichildren[i], result); + } + + // then parent + result.push_back(root->val); + } + +std::vector postorder(Node* root) { + std::vector result; + postorder(root, result); + return result; +} +``` + +You can run [this program](general_tree_post_order.cpp) to test the above functions. diff --git a/lectures/19_trees_II/general_tree_post_order.cpp b/lectures/19_trees_II/general_tree_post_order.cpp new file mode 100644 index 0000000..26264d1 --- /dev/null +++ b/lectures/19_trees_II/general_tree_post_order.cpp @@ -0,0 +1,79 @@ +#include +#include + +class Node { +public: + int val; + std::vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, std::vector _children) { + val = _val; + children = _children; + } +}; + +// make a helper function, since the original one doesn't take the vector as a parameter. +void postorder(Node* root, std::vector& result){ + // base case + if(root==NULL){ + return; + } + + // children first + int size = (root->children).size(); + for(int i=0; ichildren[i], result); + } + + // then parent + result.push_back(root->val); + } + +std::vector postorder(Node* root) { + std::vector result; + postorder(root, result); + return result; +} + +int main() { + // create tree nodes + // 1 + // / | \ + // 2 3 4 + // / \ + // 5 6 + Node* node5 = new Node(5); + Node* node6 = new Node(6); + Node* node2 = new Node(2); + Node* node3 = new Node(3, {node5, node6}); + Node* node4 = new Node(4); + Node* root = new Node(1, {node2, node3, node4}); + + // call preorder traversal + std::vector result = postorder(root); + + // print result + std::cout << "Post-order traversal: "; + for (int val : result) { + std::cout << val << " "; + } + std::cout << std::endl; + + // free memory (optional but good practice) + delete node5; + delete node6; + delete node2; + delete node3; + delete node4; + delete root; + + return 0; +} + diff --git a/lectures/19_trees_II/general_tree_pre_order.cpp b/lectures/19_trees_II/general_tree_pre_order.cpp new file mode 100644 index 0000000..59a3eee --- /dev/null +++ b/lectures/19_trees_II/general_tree_pre_order.cpp @@ -0,0 +1,74 @@ +#include +#include + +class Node { +public: + int val; + std::vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, std::vector _children) { + val = _val; + children = _children; + } +}; + +// make a helper function, since the original one doesn't take the vector as a parameter. +void preorder(Node* root, std::vector& result){ + if(root == NULL){ + return; + } + result.push_back(root->val); + + for(auto child : root->children){ + preorder(child, result); + } +} + +std::vector preorder(Node* root) { + std::vector result; + preorder(root, result); + return result; +} + +int main() { + // create tree nodes + // 1 + // / | \ + // 2 3 4 + // / \ + // 5 6 + Node* node5 = new Node(5); + Node* node6 = new Node(6); + Node* node2 = new Node(2); + Node* node3 = new Node(3, {node5, node6}); + Node* node4 = new Node(4); + Node* root = new Node(1, {node2, node3, node4}); + + // call preorder traversal + std::vector result = preorder(root); + + // print result + std::cout << "Pre-order traversal: "; + for (int val : result) { + std::cout << val << " "; + } + std::cout << std::endl; + + // free memory + // FIXME: here we delete node one by one, which is really bad, we should write a function to delete the tree. + delete node5; + delete node6; + delete node2; + delete node3; + delete node4; + delete root; + + return 0; +} +