From 4536070bcd405f57b40eff6ab0146e895bb59895 Mon Sep 17 00:00:00 2001 From: Jidong Xiao Date: Thu, 27 Mar 2025 21:09:58 -0400 Subject: [PATCH] adding binary tree test case --- lectures/21_trees_IV/README.md | 172 +++++++++++++--------------- lectures/21_trees_IV/binaryTree.png | Bin 0 -> 24281 bytes 2 files changed, 81 insertions(+), 91 deletions(-) create mode 100644 lectures/21_trees_IV/binaryTree.png diff --git a/lectures/21_trees_IV/README.md b/lectures/21_trees_IV/README.md index cf248aa..40ace4b 100644 --- a/lectures/21_trees_IV/README.md +++ b/lectures/21_trees_IV/README.md @@ -11,119 +11,109 @@ Review from Lecture 20 ## Today’s Lecture -- Red Black Trees -- B+ Trees +- Morris Traversal -## 21.1 Red-Black Trees -In addition to the binary search tree properties, the following -red-black tree properties are maintained throughout all -modifications to the data structure: +## 21.1 Morris Traversal -- Each node is either red or black. -- The root node is always black. -- The NULL child pointers are black. -- Both children of every red node are black. -- Thus, the parent of a red node must also be black. -- All paths from a particular node to a NULL child pointer contain the same - number of black nodes. +Morris Traversal is a tree traversal algorithm that allows inorder (and also preorder) traversal of a binary tree without using recursion or a stack, achieving O(1) space complexity. It modifies the tree temporarily but restores it afterward. -![alt text](Red_Black.png "Red_Black Tree example") +Instead of using extra memory (like recursion stack or an explicit stack), Morris Traversal utilizes threaded binary trees by: -What tree does our **ds_set** implementation produce if we insert the -numbers 1-14 **in order**? -  -  -  -  -  -  +- Finding the inorder predecessor of the current node. -The tree at the top is the result using a red-black tree. Notice how the tree is still quite balanced. +- Temporarily modifying the tree structure by creating threads (links) to the current node. -Visit these links for an animation of the sequential insertion and re-balancing: +- Using these links to traverse back instead of a recursive call. -http://babbage.clarku.edu/~achou/cs160fall03/examples/bst_animation/RedBlackTree-Example.html +## 21.2 Morris Traversal - In Order -https://www.cs.usfca.edu/~galles/visualization/RedBlack.html +- Start from the root. -http://www.youtube.com/watch?v=vDHFF4wjWYU&noredirect=1 +- If the left subtree is NULL, print the node and move to the right. -What is the best/average/worst case height of a red-black tree with $n$ nodes? +- If the left subtree exists, find the inorder predecessor (rightmost node in the left subtree): -  -  -  -  -  -  +- If the predecessor’s right child is NULL, set it to the current node (threading) and move left. -What is the best/average/worst case shortest-path from root to leaf node in a red-black tree with $n$ nodes? +- If the predecessor’s right child points to the current node (thread already exists), remove the thread, print the current node, and move right. -  -  -  -  -  -  - -## Exercise 21.2 -Fill in the tree on the right with the integers 1-7 to make a binary search tree. Also, color each node "red" or "black" so that the tree also fulfills the requirements of a Red-Black tree. - -![alt text](Red_Black_fillin.png "Red_Black Tree Fill In example") - -Which nodes are red? - -**Note:** Red-Black Trees are just one algorithm for **self-balancing binary search tress**. We have many more, including the AVL trees that we discussed last week. - -## 21.3 Trinary Tree - -A **trinary tree** is similar to a binary tree except that each node has at most 3 children. - -Write a **recursive** function named **EqualsChildrenSum** that takes one argument, a pointer to the root of a trinary tree, and returns true if the value at each non-leaf node is the sum of the values of all of its children and false otherwise. In -the examples below, the tree on the left will return true and the tree on the right will return false. +- Repeat until you traverse the entire tree. ```cpp -class Node { - public: - int value; - Node* left; - Node* middle; - Node* right; - }; +vector inorderTraversal(TreeNode* root) { + vector result; + TreeNode *current=root; + TreeNode *rightmost; + while(current!=NULL){ + if(current->left!=NULL){ + rightmost=current->left; + while(rightmost->right!=NULL && rightmost->right!=current){ + rightmost=rightmost->right; + } + if(rightmost->right==NULL){ /* first time */ + rightmost->right=current; + current=current->left; + }else{ /* second time */ + result.push_back(current->val); + rightmost->right=NULL; + current=current->right; + } + }else{ /* nodes which do not have left child */ + result.push_back(current->val); + current=current->right; + } + } + return result; +} ``` -![alt text](Trinary_trees.png "Trinary Trees example") -## 21.4 B+ Trees +You can test the above function using this program: [inorder_main.cpp](inorder_main.cpp). -Unlike binary search trees, nodes in B+ trees (and their predecessor, the B tree) have up to b children. Thus -B+ trees are very flat and very wide. This is good when it is very expensive to move from one node to another. -- B+ trees are supposed to be associative (i.e. they have key-value pairs), but we will just focus on the keys. -- Just like STL map and STL set, these keys and values can be any type, but keys must have an operator< -defined. -- In a B tree key-value pairs can show up anywhere in the tree, in a B+ tree all the key-value pairs are in the -leaves and the non-leaf nodes contain duplicates of some keys. -- In either type of tree, all leaves are the same distance from the root. -- The keys are always sorted in a B/B+ tree node, and there are up to b − 1 of them. They act like b − 1 binary -search tree nodes mashed together. -- In fact, with the exception of the root, nodes will always have between roughly b/2 and b − 1 keys (in our -implementation). -- If a B+ tree node has k keys key0, key1, key2, . . . , keyk−1, it will have k + 1 children. The keys in the leftmost -child must be < key0, the next child must have keys such that they are ≥key0 and < key1, and so on up to -the rightmost child which has only keys ≥keyk−1. +For this test case, -A B+ tree visualization can be seen at: https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html +![alt text](binaryTree.png "Binary Tree example") -![alt text](BplusTrees.png "Bplus_Trees example") +The testing program prints: -Considerations in a full implementation: -- What happens when we want to add a key to a node that's already full? -- How do we remove values from a node? -- How do we ensure the tree stays balanced? -- How to keep laves linked together? WHy would we want this? -- How to represent key-value pairs? +```console +$ g++ inorder_main.cpp +$ ./a.out +Inorder Traversal using Morris Traversal: +4 2 6 5 7 1 3 9 8 +``` -## 21.5 Exercise +## 21.3 Morris Traversal - Pre Order -Draw a B+ tree with b=3 with values inserted in the order 1,2,3,4,5,6. Now draw a B+ tree with b=3 and values inserted in the order 6,5,4,3,2,1. The two trees have a different number of levels. +```cpp +vector preorderTraversal(TreeNode* root) { + vector result; + int index=0; + TreeNode *current=root; + TreeNode *rightmost; + while(current != nullptr){ + if(current->left != nullptr){ + rightmost=current->left; + while(rightmost->right!=nullptr && rightmost->right!=current){ + rightmost=rightmost->right; + } + if(rightmost->right==nullptr){ /* first time */ + result.push_back(current->val); + rightmost->right=current; + current=current->left; + }else{ /* second time */ + rightmost->right=nullptr; + current=current->right; + } + }else{ /* nodes which do not have left child */ + result.push_back(current->val); + current=current->right; + } + } + return result; + } +``` +## 21.4 Morris Traversal - Post Order +```cpp +``` diff --git a/lectures/21_trees_IV/binaryTree.png b/lectures/21_trees_IV/binaryTree.png new file mode 100644 index 0000000000000000000000000000000000000000..b62d4c2869b47ecf643e3b973bdf9d9f9c6cb5c0 GIT binary patch literal 24281 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 literal 0 HcmV?d00001