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); }
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); }
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); }
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); } }