private void InsertIntoTree(int value)
        {
            int        currentLevel = 0;
            RBTreeNode node         = root;

            while (node != null)
            {
                currentLevel++;
                if (value < node.value)
                {
                    if (node.leftNode == null)
                    {
                        if (currentLevel > level)
                        {
                            level = currentLevel;
                        }
                        node.leftNode = newNode;
                        FixParent(node.leftNode, node);
                        break;
                    }
                    else
                    {
                        node = node.leftNode;
                    }
                }
                else
                {
                    if (node.rightNode == null)
                    {
                        if (currentLevel > level)
                        {
                            level = currentLevel;
                        }
                        node.rightNode = newNode;
                        FixParent(node.rightNode, node);
                        break;
                    }
                    else
                    {
                        node = node.rightNode;
                    }
                }
            }
        }
        private RBTreeNode FindValue(int value)
        {
            RBTreeNode node = root;

            while (node != null)
            {
                if (value == node.value)
                {
                    break;
                }
                if (value < node.value)
                {
                    node = node.leftNode;
                }
                else
                {
                    node = node.rightNode;
                }
            }
            return(node);
        }
        public void RemoveElement(int value)
        {
            stepsForm.AddStep("Briše se čvor s vrijednošću " + value + ".");
            Boolean replaceColorIsRed = RemoveFromTree(value);

            if (deleteChild == null)
            {
                return;
            }
            if (root == null)
            {
                return;
            }

            if (deleteChild == null || replaceColorIsRed == true)
            {
                if (deleteChild != null && deleteChild.isNullLeaf)
                {
                    if (deleteChild.parentNode.leftNode == deleteChild)
                    {
                        deleteChild.parentNode.leftNode = null;
                    }
                    else
                    {
                        deleteChild.parentNode.rightNode = null;
                    }
                    deleteChild = null;
                }
                return;
            }
            while (deleteChild != root && !deleteChild.isRed)
            {
                stepsForm.AddSubStep(string.Format("Dijete N {0} je crne boje.", deleteChild));
                if (deleteChild == deleteChild.parentNode.leftNode)
                {
                    stepsForm.AddSubStep(string.Format("N {0} je lijevo dijete roditelja P {1}.",
                                                       deleteChild, deleteChild.parentNode));
                    RBTreeNode sibling = deleteChild.parentNode.rightNode;
                    if (sibling.isRed)
                    {
                        stepsForm.AddSubStep(string.Format("S {0}, drugo dijete od P {1} je crvene boje, boji se u crnu.",
                                                           sibling, deleteChild.parentNode));
                        sibling.isRed = false;
                        stepsForm.AddSubStep(string.Format("Roditelj od N P {0} se boji u crvenu.",
                                                           deleteChild.parentNode));
                        deleteChild.parentNode.isRed = true;

                        stepsForm.AddSubStep(string.Format("Obavlja se lijeva rotacija S {0} oko P {1}.",
                                                           sibling, deleteChild.parentNode));
                        deleteChild.parentNode.rightNode = sibling.leftNode;
                        sibling.leftNode.parentNode      = deleteChild.parentNode;
                        sibling.leftNode = deleteChild.parentNode;
                        if (deleteChild.parentNode == root)
                        {
                            root = sibling;
                            sibling.parentNode = null;
                        }
                        else
                        {
                            if (deleteChild.parentNode == deleteChild.parentNode.parentNode.leftNode)
                            {
                                deleteChild.parentNode.parentNode.leftNode = sibling;
                            }
                            else
                            {
                                deleteChild.parentNode.parentNode.rightNode = sibling;
                            }
                            sibling.parentNode = deleteChild.parentNode.parentNode;
                        }
                        deleteChild.parentNode.parentNode = sibling;
                    }

                    sibling = deleteChild.parentNode.rightNode;
                    if ((sibling.leftNode == null || !sibling.leftNode.isRed) && (sibling.rightNode == null || !sibling.rightNode.isRed))
                    {
                        stepsForm.AddSubStep(string.Format("Djeca od S {0} su crna. S {0} se boji u crvenu.",
                                                           sibling));
                        sibling.isRed = true;
                        if (deleteChild.isNullLeaf)
                        {
                            if (deleteChild.parentNode.leftNode == deleteChild)
                            {
                                deleteChild.parentNode.leftNode = null;
                            }
                            else
                            {
                                deleteChild.parentNode.rightNode = null;
                            }
                        }

                        stepsForm.AddSubStep(string.Format("Roditelj od N P {0} postaje novi N.",
                                                           deleteChild.parentNode));
                        deleteChild = deleteChild.parentNode;
                    }
                    else
                    {
                        if (sibling.rightNode == null || !sibling.rightNode.isRed)
                        {
                            stepsForm.AddSubStep(string.Format("Desno dijete od S SR {0} je crne boje. Lijevo dijete od S SL {1} se boji u crnu.",
                                                               sibling.rightNode, sibling.leftNode));
                            sibling.leftNode.isRed = false;
                            stepsForm.AddSubStep(string.Format("S {0} se boji u crvenu.", sibling));
                            sibling.isRed = true;
                            stepsForm.AddSubStep(string.Format("Obavlja se desna rotacija SL {0} oko S {1}.",
                                                               sibling.leftNode, sibling));

                            deleteChild.parentNode.rightNode = sibling.leftNode;
                            sibling.leftNode.parentNode      = deleteChild.parentNode;

                            sibling.leftNode = sibling.leftNode.rightNode;
                            FixParent(sibling.leftNode, sibling);

                            deleteChild.parentNode.rightNode.rightNode = sibling;
                            sibling.parentNode = deleteChild.parentNode.rightNode;
                        }
                        sibling = deleteChild.parentNode.rightNode;
                        stepsForm.AddSubStep(string.Format("S {0} se boji u boju od roditelja P {1}.",
                                                           sibling, deleteChild.parentNode));
                        sibling.isRed = deleteChild.parentNode.isRed;
                        stepsForm.AddSubStep(string.Format("P {0} se boji u crnu.",
                                                           deleteChild.parentNode));
                        deleteChild.parentNode.isRed = false;
                        stepsForm.AddSubStep(string.Format("Desno dijete od S SR {0} se boji u crnu.",
                                                           sibling.rightNode));
                        if (sibling.rightNode != null)
                        {
                            sibling.rightNode.isRed = false;
                        }

                        stepsForm.AddSubStep(string.Format("Obavlja se lijeva rotacija S {0} oko P {1}.",
                                                           sibling, deleteChild.parentNode));
                        deleteChild.parentNode.rightNode = sibling.leftNode;
                        FixParent(deleteChild.parentNode.rightNode, deleteChild.parentNode);

                        if (deleteChild.parentNode == root)
                        {
                            root = sibling;
                            sibling.parentNode = null;
                        }
                        else
                        {
                            if (deleteChild.parentNode == deleteChild.parentNode.parentNode.leftNode)
                            {
                                deleteChild.parentNode.parentNode.leftNode = sibling;
                            }
                            else
                            {
                                deleteChild.parentNode.parentNode.rightNode = sibling;
                            }
                            sibling.parentNode = deleteChild.parentNode.parentNode;
                        }


                        sibling.leftNode = deleteChild.parentNode;
                        deleteChild.parentNode.parentNode = sibling;
                        stepsForm.AddSubStep(string.Format("Korijen {0} postaje novi N.",
                                                           root));

                        if (deleteChild.isNullLeaf)
                        {
                            if (deleteChild.parentNode.leftNode == deleteChild)
                            {
                                deleteChild.parentNode.leftNode = null;
                            }
                            else
                            {
                                deleteChild.parentNode.rightNode = null;
                            }
                        }
                        deleteChild = root;
                    }
                }
                else
                {
                    stepsForm.AddSubStep(string.Format("N {0} je desno dijete roditelja P {1}.",
                                                       deleteChild, deleteChild.parentNode));
                    RBTreeNode sibling = deleteChild.parentNode.leftNode;
                    if (sibling.isRed)
                    {
                        stepsForm.AddSubStep(string.Format("S {0}, drugo dijete od P {1} je crvene boje, boji se u crnu.",
                                                           sibling, deleteChild.parentNode));
                        sibling.isRed = false;
                        stepsForm.AddSubStep(string.Format("Roditelj od N P {0} se boji u crvenu.",
                                                           deleteChild.parentNode));
                        deleteChild.parentNode.isRed = true;

                        stepsForm.AddSubStep(string.Format("Obavlja se desna rotacija S {0} oko P {1}.",
                                                           sibling, deleteChild.parentNode));
                        deleteChild.parentNode.leftNode = sibling.rightNode;
                        sibling.rightNode.parentNode    = deleteChild.parentNode;
                        sibling.rightNode = deleteChild.parentNode;
                        if (deleteChild.parentNode == root)
                        {
                            root = sibling;
                            sibling.parentNode = null;
                        }
                        else
                        {
                            if (deleteChild.parentNode == deleteChild.parentNode.parentNode.rightNode)
                            {
                                deleteChild.parentNode.parentNode.rightNode = sibling;
                            }
                            else
                            {
                                deleteChild.parentNode.parentNode.leftNode = sibling;
                            }
                            sibling.parentNode = deleteChild.parentNode.parentNode;
                        }
                        deleteChild.parentNode.parentNode = sibling;
                    }

                    sibling = deleteChild.parentNode.leftNode;
                    if ((sibling.leftNode == null || !sibling.leftNode.isRed) && (sibling.rightNode == null || !sibling.rightNode.isRed))
                    {
                        stepsForm.AddSubStep(string.Format("Djeca od S {0} su crna. S {0} se boji u crvenu.",
                                                           sibling));
                        sibling.isRed = true;
                        if (deleteChild.isNullLeaf)
                        {
                            if (deleteChild.parentNode.leftNode == deleteChild)
                            {
                                deleteChild.parentNode.leftNode = null;
                            }
                            else
                            {
                                deleteChild.parentNode.rightNode = null;
                            }
                        }

                        stepsForm.AddSubStep(string.Format("Roditelj od N P {0} postaje novi N.",
                                                           deleteChild.parentNode));
                        deleteChild = deleteChild.parentNode;
                    }
                    else
                    {
                        if (sibling.leftNode == null || !sibling.leftNode.isRed)
                        {
                            stepsForm.AddSubStep(string.Format("Lijevo dijete od S SL {0} je crne boje. Desno dijete od S SR {1} se boji u crnu.",
                                                               sibling.leftNode, sibling.rightNode));
                            sibling.rightNode.isRed = false;
                            stepsForm.AddSubStep(string.Format("S {0} se boji u crvenu.", sibling));
                            sibling.isRed = true;
                            stepsForm.AddSubStep(string.Format("Obavlja se lijeva rotacija SR {0} oko S {1}.",
                                                               sibling.rightNode, sibling));

                            deleteChild.parentNode.leftNode = sibling.rightNode;
                            FixParent(deleteChild.parentNode.leftNode, deleteChild.parentNode);

                            sibling.rightNode = sibling.rightNode.leftNode;
                            FixParent(sibling.rightNode, sibling);
                            deleteChild.parentNode.leftNode.leftNode = sibling;
                            sibling.parentNode = deleteChild.parentNode.leftNode;
                        }
                        sibling = deleteChild.parentNode.leftNode;
                        stepsForm.AddSubStep(string.Format("S {0} se boji u boju od roditelja P {1}.",
                                                           sibling, deleteChild.parentNode));
                        sibling.isRed = deleteChild.parentNode.isRed;
                        stepsForm.AddSubStep(string.Format("P {0} se boji u crnu.",
                                                           deleteChild.parentNode));
                        deleteChild.parentNode.isRed = false;
                        stepsForm.AddSubStep(string.Format("Lijevo dijete od S SL {0} se boji u crnu.",
                                                           sibling.leftNode));
                        if (sibling.leftNode != null)
                        {
                            sibling.leftNode.isRed = false;
                        }

                        stepsForm.AddSubStep(string.Format("Obavlja se desna rotacija S {0} oko P {1}.",
                                                           sibling, deleteChild.parentNode));
                        deleteChild.parentNode.leftNode = sibling.rightNode;
                        FixParent(deleteChild.parentNode.leftNode, deleteChild.parentNode);

                        if (deleteChild.parentNode == root)
                        {
                            root = sibling;
                            sibling.parentNode = null;
                        }
                        else
                        {
                            if (deleteChild.parentNode == deleteChild.parentNode.parentNode.rightNode)
                            {
                                deleteChild.parentNode.parentNode.rightNode = sibling;
                            }
                            else
                            {
                                deleteChild.parentNode.parentNode.leftNode = sibling;
                            }
                            sibling.parentNode = deleteChild.parentNode.parentNode;
                        }

                        sibling.rightNode = deleteChild.parentNode;
                        deleteChild.parentNode.parentNode = sibling;
                        stepsForm.AddSubStep(string.Format("Korijen {0} postaje novi N.",
                                                           root));

                        if (deleteChild.isNullLeaf)
                        {
                            if (deleteChild.parentNode.rightNode == deleteChild)
                            {
                                deleteChild.parentNode.rightNode = null;
                            }
                            else
                            {
                                deleteChild.parentNode.leftNode = null;
                            }
                        }
                        deleteChild = root;
                    }
                }
            }
            stepsForm.AddSubStep(string.Format("N {0} se boji u crnu.", deleteChild));
            deleteChild.isRed = false;
        }
        public void AddElement(int value)
        {
            if (value.ToString().Length + 2 > RBTree.defaultPrintNodeLength)
            {
                int newLength = value.ToString().Length + 2;
                if (newLength % 2 == 1)
                {
                    newLength += 1;
                }
                RBTree.defaultPrintNodeLength = newLength;
            }
            newNode = new RBTreeNode(value, true);
            stepsForm.AddStep("Dodaje se novi čvor N crvene boje: " + newNode + ".");
            if (root == null)
            {
                root = newNode;
                stepsForm.AddSubStep(string.Format("Novi čvor N {0} je korijen stabla, boja mu se mijenja u crnu.",
                                                   newNode));
                root.isRed = false;
            }
            else
            {
                InsertIntoTree(value);
                RBTreeNode parent = newNode.parentNode;
                if (!parent.isRed)
                {
                    stepsForm.AddSubStep("Roditelj P " + parent + " je crne boje. Nema potrebe za rekonstrukcijom.");
                }
                while (newNode.parentNode != null && newNode.parentNode.isRed)
                {
                    stepsForm.AddSubStep(string.Format("Roditelj P {0} je crvene boje.",
                                                       newNode.parentNode));
                    RBTreeNode grandparent = newNode.parentNode.parentNode;
                    RBTreeNode uncle;
                    // p(N) == g(N).left
                    if (newNode.parentNode == newNode.parentNode.parentNode.leftNode)
                    {
                        uncle = newNode.parentNode.parentNode.rightNode;
                        stepsForm.AddSubStep(string.Format("P {0} je lijevo dijete od djeda G {1}. " +
                                                           "Ujak U {2} je desno dijete od G {1}.",
                                                           newNode.parentNode, newNode.parentNode.parentNode, uncle));
                        if (uncle != null && uncle.isRed)
                        {
                            stepsForm.AddSubStep(string.Format("U {0} je crven. P {1} postaje crn, " +
                                                               "U {0} postaje crn, G {2} postaje crven.",
                                                               uncle, newNode.parentNode, newNode.parentNode.parentNode));
                            newNode.parentNode.isRed = false;
                            uncle.isRed = false;
                            newNode.parentNode.parentNode.isRed = true;
                            newNode = newNode.parentNode.parentNode;
                        }
                        else
                        {
                            parent      = newNode.parentNode;
                            grandparent = parent.parentNode;
                            stepsForm.AddSubStep(string.Format("U {0} je crn.", uncle));
                            if (newNode == parent.rightNode)
                            {
                                stepsForm.AddSubStep(string.Format("Novi čvor N {0} je desno dijete od P {1}. " +
                                                                   "Obavlja se lijeva rotacija N {0} oko P {1}.",
                                                                   newNode, parent));
                                grandparent.leftNode = newNode;
                                FixParent(grandparent.leftNode, grandparent);

                                parent.rightNode = newNode.leftNode;
                                FixParent(parent.rightNode, parent);

                                newNode.leftNode = parent;
                                FixParent(newNode.leftNode, newNode);

                                stepsForm.AddSubStep(string.Format("N {0} postaje P {1}.",
                                                                   newNode, parent));
                                newNode = parent;
                            }
                            RBTreeNode tempParent           = newNode.parentNode;
                            RBTreeNode tempGrandparent      = tempParent.parentNode;
                            RBTreeNode tempGrandGrandparent = tempGrandparent.parentNode;
                            stepsForm.AddSubStep(string.Format("Obavlja se desna rotacija roditelja od N p(N) {0} oko djeda od N g(N) {1}.",
                                                               tempParent, tempGrandparent));

                            Rotation(newNode.parentNode, newNode.parentNode.parentNode, true);
                            stepsForm.AddSubStep(string.Format("P {0} postaje crn, G {1} postaje crven.",
                                                               newNode.parentNode, newNode.parentNode.parentNode));
                            if (newNode.parentNode != null)
                            {
                                newNode.parentNode.isRed = false;
                            }
                            newNode.parentNode.parentNode.isRed = true;
                        }
                    }
                    else
                    {
                        uncle = newNode.parentNode.parentNode.leftNode;
                        stepsForm.AddSubStep(string.Format("P {0} je desno dijete od djeda G {1}. Ujak U {2} je lijevo dijete od G {1}.",
                                                           parent, grandparent, uncle));
                        if (uncle != null && uncle.isRed)
                        {
                            stepsForm.AddSubStep(string.Format("U {0} je crven. P {1} postaje crn, U {0} postaje crn, G {2} postaje crven.",
                                                               uncle, newNode.parentNode, newNode.parentNode.parentNode));
                            newNode.parentNode.isRed = false;
                            uncle.isRed = false;
                            newNode.parentNode.parentNode.isRed = true;
                            newNode = newNode.parentNode.parentNode;
                        }
                        else
                        {
                            parent      = newNode.parentNode;
                            grandparent = parent.parentNode;
                            stepsForm.AddSubStep(string.Format("U {0} je crn.",
                                                               uncle));
                            if (newNode == parent.leftNode)
                            {
                                stepsForm.AddSubStep(string.Format("Novi čvor N {0} je lijevo dijete od P {1}. Obavlja se desna rotacija N {0} oko P {1}.",
                                                                   newNode, parent));
                                grandparent.rightNode = newNode;
                                FixParent(grandparent.rightNode, grandparent);

                                parent.leftNode = newNode.rightNode;
                                FixParent(parent.leftNode, parent);
                                newNode.rightNode = parent;
                                FixParent(newNode.rightNode, newNode);
                                stepsForm.AddSubStep(string.Format("N {0} postaje P {1}.",
                                                                   newNode, parent));
                                newNode = parent;
                            }
                            RBTreeNode tempParent           = newNode.parentNode;
                            RBTreeNode tempGrandparent      = tempParent.parentNode;
                            RBTreeNode tempGrandGrandparent = tempGrandparent.parentNode;
                            stepsForm.AddSubStep(string.Format("Obavlja se lijeva rotacija roditelja od N p(N) {0} oko djeda od N g(N) {1}.",
                                                               tempParent, tempGrandparent));
                            Rotation(newNode.parentNode, newNode.parentNode.parentNode, false);
                            stepsForm.AddSubStep(string.Format("P {0} postaje crn, G {1} postaje crven.",
                                                               newNode.parentNode, newNode.parentNode.parentNode));
                            if (newNode.parentNode != null)
                            {
                                newNode.parentNode.isRed = false;
                            }
                            grandparent.isRed = true;
                        }
                    }
                }
                RBTreeNode node = parent;
                while (node.parentNode != null)
                {
                    node = node.parentNode;
                }
                if (node.isRed)
                {
                    stepsForm.AddSubStep(string.Format("Korijen {0} postaje crn.", root));
                    node.isRed = false;
                }
            }
        }
 public void Reset()
 {
     root    = null;
     newNode = null;
     level   = 0;
 }
        private Boolean RemoveFromTree(int value)
        {
            RBTreeNode deleteNode = FindValue(value);

            if (deleteNode == null)
            {
                return(false);
            }
            if (deleteNode == root && deleteNode.leftNode == null && deleteNode.rightNode == null)
            {
                root = null;
                return(false);
            }
            deleteChild = null;
            if (deleteNode == null)
            {
                return(true);
            }
            RBTreeNode replaceNode  = FindReplace(deleteNode);
            Boolean    replaceColor = replaceNode.isRed;

            if (replaceNode == deleteNode)
            {
                // delnode != root
                if (deleteNode.parentNode != null)
                {
                    deleteChild            = new RBTreeNode(-1, false);
                    deleteChild.isNullLeaf = true;
                    deleteChild.parentNode = deleteNode.parentNode;
                    if (deleteNode.parentNode.leftNode == deleteNode)
                    {
                        deleteNode.parentNode.leftNode = deleteChild;
                    }
                    else
                    {
                        deleteNode.parentNode.rightNode = deleteChild;
                    }
                }
                deleteNode = null;
                return(replaceColor);
            }
            if (replaceNode.value <= deleteNode.value)
            {
                if (deleteNode.leftNode == replaceNode)
                {
                    deleteNode.leftNode = replaceNode.leftNode;
                    if (deleteNode.leftNode != null)
                    {
                        deleteNode.leftNode.parentNode = deleteNode;
                        deleteChild = deleteNode.leftNode;
                    }
                    else
                    {
                        deleteChild            = new RBTreeNode(-1, false);
                        deleteChild.isNullLeaf = true;
                        deleteNode.leftNode    = deleteChild;
                    }
                    deleteChild.parentNode = deleteNode;
                    deleteNode.value       = replaceNode.value;
                    replaceNode            = null;
                }
                else
                {
                    RBTreeNode parentOfReplace = replaceNode.parentNode;
                    parentOfReplace.rightNode = replaceNode.leftNode;

                    if (parentOfReplace.rightNode == null)
                    {
                        deleteChild               = new RBTreeNode(-1, false);
                        deleteChild.isNullLeaf    = true;
                        parentOfReplace.rightNode = deleteChild;
                        deleteChild.parentNode    = parentOfReplace;
                    }
                    else
                    {
                        if (parentOfReplace.rightNode.leftNode != null)
                        {
                            parentOfReplace.rightNode.leftNode.parentNode = parentOfReplace;
                            deleteChild = parentOfReplace.rightNode.leftNode;
                        }
                        else
                        {
                            deleteChild                        = new RBTreeNode(-1, false);
                            deleteChild.isNullLeaf             = true;
                            parentOfReplace.rightNode.leftNode = deleteChild;
                            deleteChild.parentNode             = parentOfReplace;
                        }
                    }


                    deleteNode.value = replaceNode.value;
                    replaceNode      = null;
                }
            }
            else
            {
                if (deleteNode.rightNode == replaceNode)
                {
                    deleteNode.rightNode = replaceNode.rightNode;
                    if (deleteNode.rightNode != null)
                    {
                        deleteChild = deleteNode.rightNode;
                    }
                    else
                    {
                        deleteChild            = new RBTreeNode(-1, false);
                        deleteChild.isNullLeaf = true;
                        deleteNode.rightNode   = deleteChild;
                    }
                    deleteChild.parentNode = deleteNode;
                    deleteNode.value       = replaceNode.value;
                    replaceNode            = null;
                }
                else
                {
                    RBTreeNode parentOfReplace = replaceNode.parentNode;
                    parentOfReplace.leftNode = replaceNode.rightNode;

                    if (parentOfReplace.leftNode == null)
                    {
                        deleteChild              = new RBTreeNode(-1, false);
                        deleteChild.isNullLeaf   = true;
                        parentOfReplace.leftNode = deleteChild;
                        deleteChild.parentNode   = parentOfReplace;
                    }
                    else
                    {
                        if (parentOfReplace.leftNode.rightNode != null)
                        {
                            parentOfReplace.leftNode.rightNode.parentNode = parentOfReplace;
                            deleteChild = parentOfReplace.leftNode.rightNode;
                        }
                        else
                        {
                            deleteChild                        = new RBTreeNode(-1, false);
                            deleteChild.isNullLeaf             = true;
                            parentOfReplace.leftNode.rightNode = deleteChild;
                            deleteChild.parentNode             = parentOfReplace;
                        }
                    }


                    deleteNode.value = replaceNode.value;
                    replaceNode      = null;
                }
            }
            return(replaceColor);
        }
        private void Rotation(RBTreeNode rotated, RBTreeNode centered, Boolean leftSide)
        {
            RBTreeNode parentCentered = centered.parentNode;

            // p(N) == root
            if (parentCentered == null)
            {
                if (leftSide)
                {
                    // g(N).left = p(N).right
                    centered.leftNode = rotated.rightNode;
                    FixParent(centered.leftNode, centered);
                    // p(N).right = g(N)
                    rotated.rightNode = centered;
                    FixParent(rotated.rightNode, rotated);
                }
                else
                {
                    // g(N).right = p(N).left
                    centered.rightNode = rotated.leftNode;
                    FixParent(centered.rightNode, centered);
                    // p(N).left = g(N)
                    rotated.leftNode = centered;
                    FixParent(rotated.leftNode, rotated);
                }

                root = rotated;
                rotated.parentNode = parentCentered;
            }
            else if (leftSide)
            {
                if (parentCentered.leftNode == centered)
                {
                    // p(g(N)).left = p(N)
                    parentCentered.leftNode = rotated;
                    FixParent(parentCentered.leftNode, parentCentered);
                    // g(N).left = p(N).right
                    centered.leftNode = rotated.rightNode;
                    FixParent(centered.leftNode, centered);
                    // p(N).right = g(N)
                    rotated.rightNode = centered;
                    FixParent(rotated.rightNode, rotated);
                }
                else
                {
                    // p(g(N)).right = p(N)
                    parentCentered.rightNode = rotated;
                    FixParent(parentCentered.rightNode, parentCentered);
                    // g(N).left = p(N).right
                    centered.leftNode = rotated.rightNode;
                    FixParent(centered.leftNode, centered);
                    // p(N).right = g(N)
                    rotated.rightNode = centered;
                    FixParent(rotated.rightNode, rotated);
                }
            }
            else
            {
                if (parentCentered.rightNode == centered)
                {
                    // p(g(N)).right = p(N)
                    parentCentered.rightNode = rotated;
                    FixParent(parentCentered.rightNode, parentCentered);
                    // g(N).right = p(N).left
                    centered.rightNode = rotated.leftNode;
                    FixParent(centered.rightNode, centered);
                    // p(N).left = g(N)
                    rotated.leftNode = centered;
                    FixParent(rotated.leftNode, rotated);
                }
                else
                {
                    // p(g(N)).left = p(N)
                    parentCentered.leftNode = rotated;
                    FixParent(parentCentered.leftNode, parentCentered);
                    // g(N).right = p(N).left
                    centered.rightNode = rotated.leftNode;
                    FixParent(centered.rightNode, centered);
                    // p(N).left = g(N)
                    rotated.leftNode = centered;
                    FixParent(rotated.leftNode, rotated);
                }
            }
        }