private void RebalancePostInsertion(RBTreeNode newNode) { /** * Insert function places newNode as an appropriate leaf for a regular BST but * not necessarily a Red-black tree. Check if newNode's parent is RED (ie. if it * breaks a only red-black tree condition). If so, use the RED and BLACK labels * of newNode's parent, grandparent, and/or pibling (aunt/uncle) to balance. * * Note on conceptualizing this process: * At this point, newNode is a RED leaf whose addition may cause the tree to * not meet the required RED-BLACK conditions (noted in class description) * such that it is imbalanced beyond the red-black tree threshold. In order * to correct for this, we re-balance and/or recolor the subtree rooted at * newNode's grandparent. We perform this process iteratively, reassigning * newNode to its decendants (parents/grandparents), until we reach the root. * At no point do we consider ancestors of newNode. * * See this page for a more detailed overview of the process: * https://www.geeksforgeeks.org/red-black-tree-set-2-insert/ */ if (newNode.GrandParent() == null) { return; } RBTreeNode u; // Will represent pibling (aunt/uncle) or parent of newNode. // ie. given newNode's grandparent (gP), u can be either gP's // left or right child while (newNode.Parent().IsRed()) { // Case: p is the RIGHT child of gP: if (newNode.Parent() == newNode.GrandParent().Right()) { // Set u as the (LEFT) pibling of newNode u = newNode.GrandParent().Left(); // Case: u exists and is RED: set both u & p to BLACK, set gP to RED, // assign newNode = gP if (u != null && u.IsRed()) { u.SetBlack(); newNode.Parent().SetBlack(); newNode.GrandParent().SetRed(); newNode = newNode.GrandParent(); } else // Case: the (LEFT) pibling of newNode is BLACK // Case: newNode is the left child of p: assign newNode = p and // right rotate newNode { if (newNode == newNode.Parent().Left()) { newNode = newNode.Parent(); RotateRight(newNode); } // Set p to BLACK and gP to RED. Then left rotate gP. newNode.Parent().SetBlack(); newNode.GrandParent().SetRed(); RotateLeft(newNode.GrandParent()); } } else // Case: p is the LEFT child of gP: // Assign u as the (RIGHT) pibling of newNode { u = newNode.GrandParent().Right(); // Case: u is RED: set the color of both children of gP to BLACK, set // gp to RED. Assign gP = newNode. if (u != null && u.IsRed()) { u.SetBlack(); newNode.Parent().SetBlack(); newNode.GrandParent().SetRed(); newNode = newNode.GrandParent(); } else { // Case: newNode is the right child of p then: set p = newNode. // Then left rotate newNode. if (newNode == newNode.Parent().Right()) { newNode = newNode.Parent(); RotateLeft(newNode); } // Set color of p as BLACK and color of gP as RED. Then right // rotate gP. newNode.Parent().SetBlack(); newNode.GrandParent().SetRed(); RotateRight(newNode.GrandParent()); } } if (newNode == Root) { break; } } Root.SetBlack(); }