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 0000000..b62d4c2 Binary files /dev/null and b/lectures/21_trees_IV/binaryTree.png differ