280 likes | 282 Views
This presentation covers different implementations of Red Black Trees, including recursive and iterative approaches, with simplified code examples. Follow along with the textbook.
E N D
Implementing Red Black Trees Ellen Walker CPSC 201 Data Structures Hiram College
Implementing Red-Black Trees • Several implementations are possible (and many are on the Internet) • Some include parent links in RedBlackNodes - can be iterative • Textbook’s is recursive, recognizing need for rotations on the way back up the tree (after recursive call) • These slides follow your textbook, but… • Code here is incomplete • In places, code has been simplified for presentation • For complete, correct code, see your textbook and/or the book code
About These Slides • Follow textbook’s presentation but… • … code is incomplete • … code is slightly simplified for ease of presentation • Example: casts are removed • Use these notes as a guide for understanding when reading the actual textbook code
Classes (Koffman & Wolfgang) SearchTree (abstract class) BinarySearchTree BSTWithRotate (Adds RotateLeft and RotateRight) RBTree
Single Rotation (RotateRight) 4 temp root 8 temp 4 3 8 root 6 3 6 temp = root.left; root.left = temp.right; temp.right = root; return temp;
Double Rotation 8 root 8 6 4 4 6 6 5 8 4 5 5 root.left = rotateLeft(root.left); return RotateRight(root);
RedBlackNode<E> • E data • Data contained in this node • RedBlackNode left, RedBlackNode right • References to children • boolean isRed • Color of this node (true means Red) • Set to true in constructor, because all nodes (except root) are red when added
Recall: BST Recursive Add If (item.equals(localRoot.data)) addreturn = null; //duplicates not added Return localRoot; If (item.compareTo(localRoot.data)<0) Add to the left return localRoot; Else Add to the right return localRoot;
Recall: BST Recursive Add (left side) If localRoot.left == null localRoot.left = new Node(item); return localRoot; Else localRoot.left = add(localRoot.left,item); return localRoot;
Add Recursion • Base case at leaf of tree • Create and link a new node • Recursive case • Recursively add on the correct side • Link result of recursion back into the tree, or the changes will be lost! • localRoot.left = add(localRoot.left, item); //not just add(localRoot.left, item);
Top Down Insertion Algorithm • Search the binary tree in the usual way for the insertion algorithm • If you pass a 4-node (black node with two red children) on the way down, split it • Insert the node as a red child, and use the split algorithm to adjust via rotation if the parent is red also. • Force the root to be black after every insertion.
RBT Adding to the Left If localRoot.left == null localRoot.left = new Node(item); return localRoot; Else //Split me if I’m a 4-node moveBlackDown(localRoot); localRoot.left = add(localRoot.left, item); //Deal with consecutive red child & grandchild //case 1: red left child with red left grandchild //case 2: red left child with red right grandchild
RotateRight to Fix Left-Left Reds 4 localRoot 8 4 3 8 6 3 6 localRoot.left.isRed = false; localRoot.isRed = true; Return rotateRight(localRoot);
Double Rotation to Fix Left-Right Reds 8 localRoot 8 6 4 4 6 6 5 8 4 5 5 localRoot.left = rotateLeft(localRoot.left); localRoot.left.isRed = false; localRoot.isRed = true; return RotateRight(localRoot);
Putting the code all together • Insert appropriate tests to recognize the various red-red cases • Repeat all the “left code” for the right side • Swap “left” vs. “right” everywhere • Write the “starter add method” • Deals with an empty tree • Makes the root black at the end
Starter Method If (root == null) { root = new RedBlackNode<E> (item); root.isRed = false; //root is always black addReturn = true; //item was added } Else { root = add(root, item); //sets addReturn root.isRed = false; //root is always black } return addReturn;
Insert 1, 2, 3 2 1 1 1 3 2 2 Left single rotation 3 Insert red leaf (2 consecutive red nodes!)
Continued: Insert 4, 5 2 2 2 1 3 1 3 1 4 3 4 4 5 4-node (2 red children) split on the way down Root remains black 5 Single rotation to avoidconsecutive red nodes
Continued, Insert 9, 6 2 2 2 1 4 1 4 1 4 3 3 5 5 3 6 9 9 5 9 4-node (3,4,5) split on the way down, 4 is now red (passed up) Double rotation 6
Deletion Algorithm • Find the node to be deleted (NTBD) • On the way down, if you pass a 2-node upgrade it by borrowing from its neighbor and/or parent • If the node is not a leaf node, • Find its immediate successor, upgrading all 2-nodes • Swap value of leaf node with value of NTBD • Remove the current leaf node, which is now NTBD (because of swap, if it happened)
Red-black “neighbor” of a node • Let X be a 2-node to be deleted • If X is its parent’s left child, X’s right neighbor can be found by: • Let S = parent’s right child. If S is black, it is the neighbor • Otherwise, S’s left child is the neighbor. • If X is parent’s left child, then X’s left neighbor is grandparent’s left child.
Neighbor examples 2 Right neighbor of 1 is 3 Right neighbor of 3 is 5 Left neighbor of 5 is 3 Left neighbor of 3 is 1 1 4 3 5 9
Upgrade a 2-node • Find the 2-node’s neighbor (right if any, otherwise left) • If neighbor is also a 2-node (2 black children) • Create a 4-node from neighbors and their parent. • If neighbors are actually siblings, this is a color swap. • Otherwise, it requires a rotation • If neighbor is a 3-node or 4-node (red child) • Move “inner value” from neighbor to parent, and “dividing value” from parent to 2-node. • This is a rotation
Deletion Examples (Delete 1) 2 4 2 6 1 4 1 3 5 9 3 6 Make a 4-node from 1, sibling 3, and “divider value” 2. [Single rotation of 2,4,6] 5 9
Delete 6 4 4 2 6 2 9 3 5 9 3 5 6 4 Upgrade 6 by color flip, swap with successor (9) 2 9 3 5
Delete 4 2 2 2 1 5 1 5 1 4 3 3 6 6 3 6 4 9 9 5 9 No 2-nodes to upgrade, swap with successor (5)
Delete 2 2 2 1 5 1 6 3 6 5 9 9 3 Find 2-node enroute to successor (3) Neighbor is 3-node (6,9) Shift to get (3,5) and 9 as children, 6 up to parent. Single rotation
Delete 2 (cont’d) 3 3 1 6 1 6 5 5 9 9 2 Swap with successor Remove leaf