Ejemplo n.º 1
0
        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();
        }