Пример #1
0
        public void Insert(int data)
        {
            RBTreeNode newNode;
            RBTreeNode y = null;
            RBTreeNode x;

            if (Root == null)   // Empty tree
            {
                Root = new RBTreeNode(data, red: false);
                return;
            }

            newNode = new RBTreeNode(data); // Instantiate as Red node
            x       = Root;

            //  Traverse until y is a leaf in a location where x doesn’t violate
            //  the tree’s ordering
            while (x != null)
            {
                y = x;
                if (newNode < x)
                {
                    x = x.Left();
                }
                else
                {
                    x = x.Right();
                }
            }

            //  Make newNode child of y
            newNode.SetParent(y);
            if (newNode < y)
            {
                y.SetLeft(newNode);
            }
            else
            {
                y.SetRight(newNode);
            }

            RebalancePostInsertion(newNode);
        }
Пример #2
0
        private void RotateLeft(RBTreeNode x)
        {
            /**
             * Make right subtree left subtree */

            // setup x & y
            RBTreeNode y = x.Right();

            x.SetRight(y.Left());

            // if y has a left child, make x the parent of the left child of y.
            if (y.Left() != null)
            {
                y.Left().SetParent(x);
            }
            y.SetParent(x.Parent());

            // if x has no parent, make y the root of the tree.
            if (x.Parent() == null)
            {
                Root = y;
            }

            // else if x is the left child of p, make y the left child of p.
            else if (x == x.Parent().Left())
            {
                x.Parent().SetLeft(y);
            }

            // else make y the right child of p
            else
            {
                x.Parent().SetRight(y);
            }

            // make y the parent of x
            y.SetLeft(x);
            x.SetParent(y);
        }
Пример #3
0
        private void RotateRight(RBTreeNode y)
        {
            /**
             * Make left subtree right subtree */

            // setup x & y
            RBTreeNode x = y.Left();

            y.SetLeft(x.Right());

            // if x has a right child, make y the parent of the right child of x.
            if (x.Right() != null)
            {
                x.Right().SetParent(y);
            }
            x.SetParent(y.Parent());

            // if y has no parent, make x the root of the tree.
            if (y.Parent() == null)
            {
                Root = x;
            }

            // else if y is the right child of its parent p, make x the right child of p.
            else if (y == y.Parent().Right())
            {
                y.Parent().SetRight(x);
            }

            // else assign x as the left child of p.
            else
            {
                y.Parent().SetLeft(x);
            }

            // make x the parent of y.
            x.SetRight(y);
            y.SetParent(x);
        }
Пример #4
0
        private void Transplant(RBTreeNode oldNode, RBTreeNode newNode)
        {
            // Replace oldNode with newNode
            RBTreeNode parent = oldNode.Parent();

            if (parent == null)
            {
                Root = newNode;
            }
            else if (oldNode == parent.Left())
            {
                parent.SetLeft(newNode);
            }
            else
            {
                parent.SetRight(newNode);
            }

            // Null check for when newNode is null
            if (newNode != null)
            {
                newNode.SetParent(parent);
            }
        }
Пример #5
0
 public void SetRight(RBTreeNode rightChild)
 {
     RightChild = rightChild;
 }
Пример #6
0
 public void SetLeft(RBTreeNode leftChild)
 {
     LeftChild = leftChild;
 }
Пример #7
0
 public void SetParent(RBTreeNode parent)
 {
     ParentNode = parent;
 }
Пример #8
0
        public string VisualizeTree(RBTreeNode node, int verticalSpacing,
                                    int indentPerLevel, bool print = true,
                                    bool safeChars = true)
        {
            /**
             * Parameters:
             *  node:   RBTree node treated as the root in the visualization
             *  verticalSpacing: number of lines between each displayed node
             *  indentPerLevel: width of the line separating each level of the tree
             *  print: if true, write output to console
             *  safeChars: if true, use standard dash '-' character for horizontal lines.
             *             else, use the special full-width horizontal bar character
             *             which seems to occasionally break StringBuilder
             *
             * Note: functionality inspired by the following Baeldung article:
             *      https://www.baeldung.com/java-print-binary-tree-diagram */

            string pointerChars;

            if (safeChars)
            {
                pointerChars = new string('-', indentPerLevel);
            }
            else
            {
                pointerChars = new string('─', indentPerLevel);
            }


            string oneChildPointer    = "└" + pointerChars;
            string twoChildrenPointer = "├" + pointerChars;

            string paddingChars      = new string(' ', indentPerLevel + 1);
            string twoChildrenIndent = "│" + paddingChars;
            string whiteSpaceIndent  = " " + paddingChars;

            void Traverse(StringBuilder sb, String padding, String pointer,
                          RBTreeNode node, bool hasRightSibling)
            {
                if (node == null || node.IsEmpty())
                {
                    return;
                }

                // Append vertical line spacing
                for (int i = 0; i < verticalSpacing; i++)
                {
                    sb.Append("\n" + padding);
                    if (pointer == whiteSpaceIndent)
                    {
                        sb.Append('|');
                    }
                    else
                    {
                        sb.Append("| ");
                    }
                }

                // Append line rows with values
                sb.Append($"\n{padding}{pointer} {node.VisualizerString()}");

                // Calculate and append padding next row
                StringBuilder paddingSB = new StringBuilder(padding);

                if (hasRightSibling)
                {
                    paddingSB.Append(twoChildrenIndent);
                }
                else
                {
                    paddingSB.Append(whiteSpaceIndent);
                }
                string newPadding = paddingSB.ToString();

                // Determine pointer for next row
                string pointerLeft =
                    (node.Right() != null) ? twoChildrenPointer : oneChildPointer;

                // Recurse
                Traverse(sb, newPadding, pointerLeft, node.Left(), node.Right() != null);
                Traverse(sb, newPadding, oneChildPointer, node.Right(), false);
            }

            string TraversePreOrder(RBTreeNode root)
            {
                // Handle root
                if (root == null)
                {
                    return("Empty binary tree.");
                }
                StringBuilder sb = new StringBuilder();

                sb.Append(root.GetData() + " (B)");

                // Determine initial pointer
                string pointerLeft =
                    (root.Right() != null) ? twoChildrenPointer : oneChildPointer;

                Traverse(sb, "", pointerLeft, root.Left(), root.Right() != null);
                Traverse(sb, "", oneChildPointer, root.Right(), false);
                return(sb.ToString());
            }

            string prettyBinaryTree = TraversePreOrder(node);

            if (print)
            {
                Console.WriteLine(prettyBinaryTree);
            }
            return(prettyBinaryTree);
        }
Пример #9
0
        public string PrintTreeTraversalOrder(int order, RBTreeNode treeRoot)
        {
            /**
             * Output to console & return as string.
             *
             * Parameters:
             *  order:  1 -> Inorder
             *          2 -> Preorder
             *          3 -> Postorder
             *  treeRoot: the root node of the Red-Black tree to traverse   */

            // Helpers:
            void PrintInOrder(RBTreeNode currRoot)
            {
                if (currRoot == null)
                {
                    return;
                }
                PrintInOrder(currRoot.Left());
                Console.Write($"{currRoot.GetData()}, ");
                PrintInOrder(currRoot.Right());
            }

            void PrintPreOrder(RBTreeNode currRoot)
            {
                if (currRoot == null)
                {
                    return;
                }
                Console.Write($"{currRoot.GetData()}, ");
                PrintPreOrder(currRoot.Left());
                PrintPreOrder(currRoot.Right());
            }

            void PrintPostOrder(RBTreeNode currRoot)
            {
                if (currRoot == null)
                {
                    return;
                }
                PrintPostOrder(currRoot.Left());
                PrintPostOrder(currRoot.Right());
                Console.Write($"{currRoot.GetData()}, ");
            }

            // Write to string using console:
            StringWriter sw = new StringWriter();

            Console.SetOut(sw);
            if (order == 1)
            {
                Console.Write("Inorder traversal: ");
                PrintInOrder(treeRoot);
            }
            else if (order == 2)
            {
                Console.Write("Preorder traversal: ");
                PrintPreOrder(treeRoot);
            }
            else if (order == 3)
            {
                Console.Write("Postorder traversal: ");
                PrintPostOrder(treeRoot);
            }
            else
            {
                throw new Exception(
                          $"Invalid order parameter {order} when calling traverse.");
            }

            // store string & remove trailing comma & space
            String output = sw.ToString();

            output = output.Remove(output.Length - 2, 2);

            // close StringWriter, reset standard out, print, and return
            sw.Close();
            var standardOutput = new StreamWriter(Console.OpenStandardOutput());

            standardOutput.AutoFlush = true;
            Console.SetOut(standardOutput);
            Console.WriteLine(output);
            return(output);
        }
Пример #10
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();
        }
Пример #11
0
        public void Delete(RBTreeNode node, int value)
        {
            // Traverse until we find nodeToDelete
            RBTreeNode nodeToDelete = null;

            while (node != null)
            {
                if (node.GetData() == value)
                {
                    nodeToDelete = node;
                    break;
                }
                node = (value < node.GetData()) ? node.Left() : node.Right();
            }
            if (nodeToDelete == null)
            {
                throw new Exception("Cannot find node to delete with " +
                                    $"value {value} in Red Black Tree");
            }

            RBTreeNode x, y;

            // Save the color of nodeToDelete
            bool originallyRed = nodeToDelete.IsRed();

            // If nodeToDelete only has left children, replace with its left subtree
            if (nodeToDelete.Left() == null || nodeToDelete.Left().IsEmpty())
            {
                x = nodeToDelete.Right();
                if (x == null)
                {
                    x = Leaf;
                }
                Transplant(nodeToDelete, x);

                // If nodeToDelete only has right children, replace with its right subtree
            }
            else if (nodeToDelete.Right() == null || nodeToDelete.Right().IsEmpty())
            {
                x = nodeToDelete.Left();
                if (x == null)
                {
                    x = Leaf;
                }
                Transplant(nodeToDelete, x);
            }
            else        // nodeToDelete either has two children or is a leaf

            // y = smallest node whose value is greater than that of nodeToDelete
            // will replace nodeToDelete
            {
                y             = Minimum(nodeToDelete.Right());
                originallyRed = y.IsRed();

                // x = subtree root with values greater than y
                x = y.Right();
                if (x == null)
                {
                    x = Leaf;
                }

                // if y is a child of nodeToDelete, x is already stored in the right place
                if (y.Parent() == nodeToDelete)
                {
                    x.SetParent(y);
                }
                else     // else replace y with its right subtree and update attributes
                {
                    Transplant(y, y.Right());
                    y.SetRight(nodeToDelete.Right());
                    y.Right().SetParent(y);
                }

                // replace nodeToDelete with y and update attributes
                Transplant(nodeToDelete, y);
                y.SetLeft(nodeToDelete.Left());
                y.Left().SetParent(y);

                // y will replace nodeToDelete's location in tree, update its color
                if (originallyRed)
                {
                    y.SetRed();
                }
                else
                {
                    y.SetBlack();
                }
            }
            if (!(originallyRed))
            {
                RebalancePostDeletion(x);
            }
        }
Пример #12
0
        private void RebalancePostDeletion(RBTreeNode node)
        {
            // Very similar to RebalancePostInsertion function
            // node is the node in the location of/closest to the node just deleted
            RBTreeNode s; // represents sibbling of node

            while (node != Root && node.IsBlack())
            {
                if (node == node.Parent().Left())
                {
                    s = node.Parent().Right();

                    if (s.IsRed())   // case 1
                    {
                        s.SetBlack();
                        node.Parent().SetRed();
                        RotateLeft(node.Parent());
                        s = node.Parent().Right();
                    }

                    if (s.Left().IsBlack() && s.Right().IsBlack())   // case 2
                    {
                        s.SetRed();
                        node = node.Parent();
                    }
                    else
                    {
                        if (s.Right().IsBlack())   // case 3
                        {
                            s.Left().SetBlack();
                            s.SetRed();
                            RotateRight(s);
                            s = node.Parent().Right();
                        }

                        if (s.Parent().IsRed())
                        {
                            s.SetRed();
                        }
                        else
                        {
                            s.SetBlack();
                        }

                        node.Parent().SetBlack();
                        s.Right().SetBlack();
                        RotateLeft(s.Parent());
                        node = Root;
                    }
                }
                else
                {
                    s = node.Parent().Left();

                    if (s.IsRed())
                    {
                        s.SetBlack();
                        node.Parent().SetRed();
                        RotateRight(node.Parent());
                        s = node.Parent().Left();
                    }
                    if (s.Right() == null)
                    {
                        s.SetRight(Leaf);
                    }
                    if (s.Left() == null)
                    {
                        s.SetLeft(Leaf);
                    }
                    if (s.Right().IsBlack() && s.Left().IsBlack())
                    {
                        s.SetRed();
                        node = node.Parent();
                    }
                    else
                    {
                        if (s.Left().IsBlack())
                        {
                            s.Right().SetBlack();
                            s.SetRed();
                            RotateLeft(s);
                            s = node.Parent().Left();
                        }

                        if (s.Parent().IsRed())
                        {
                            s.SetRed();
                        }
                        else
                        {
                            s.SetBlack();
                        }

                        node.Parent().SetBlack();
                        s.Left().SetBlack();
                        RotateRight(node.Parent());
                        node = Root;
                    }
                }
            }
            node.SetBlack();
        }