Example #1
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);
        }
Example #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);
        }
Example #3
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);
        }
Example #4
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);
            }
        }