/// <summary> /// Perform rebalancing on the red-black tree for a deletion. O(lg n). /// If we broke the tree by moving a black node, we need to reorder /// and/or recolor part of it. This is not pretty, and is basically /// derived from the algorithm in Cormen/Leiserson/Rivest, just like /// every other red-black tree implementation. We have, however, gone /// to the necessary work to drop out the required sentinel value in /// their version, so this is a little more flexible. /// </summary> /// <param name="child">The child that was removed.</param> /// <param name="parent">The parent it was removed from.</param> /// <param name="rightSide">Which side of the parent it was removed from.</param> private void DetachFixup(WeightedRedBlackTreeNode <K, V> child, WeightedRedBlackTreeNode <K, V> parent, bool rightSide) { while (child != Root && child.IsBlack()) { if (!rightSide) { WeightedRedBlackTreeNode <K, V> other = parent.Right; if (other.IsRed()) { other.MakeNodeBlack(); parent.MakeNodeRed(); RotateLeft(parent); other = parent.Right; } if (other == null || (other.Left.IsBlack() && other.Right.IsBlack())) { other.MakeNodeRed(); child = parent; } else { if (other.Right.IsBlack()) { other.Left.MakeNodeBlack(); other.MakeNodeRed(); RotateRight(other); other = parent.Right; } if (parent.IsRed()) { other.MakeNodeRed(); } else { other.MakeNodeBlack(); } parent.MakeNodeBlack(); other.Right.MakeNodeBlack(); RotateLeft(parent); child = Root; } } else { WeightedRedBlackTreeNode <K, V> other = parent.Left; if (other.IsRed()) { other.MakeNodeBlack(); parent.MakeNodeRed(); RotateRight(parent); other = parent.Left; } if (other == null || (other.Right.IsBlack() && other.Left.IsBlack())) { other.MakeNodeRed(); child = parent; } else { if (other.Left.IsBlack()) { other.Right.MakeNodeBlack(); other.MakeNodeRed(); RotateLeft(other); other = parent.Left; } if (parent.IsRed()) { other.MakeNodeRed(); } else { other.MakeNodeBlack(); } parent.MakeNodeBlack(); other.Left.MakeNodeBlack(); RotateRight(parent); child = Root; } } parent = child.Parent; if (child != Root) { rightSide = (child == parent.Right); } } child.MakeNodeBlack(); }
/// <summary> /// This corrects the tree for a newly-inserted node, rotating it as /// necessary to keep it balanced. The algorithm is the same as RB-INSERT in [1], /// minus the first line that performs TREE-INSERT. O(lg n). /// </summary> /// <param name="node">The newly-inserted node.</param> protected void InsertFixup(WeightedRedBlackTreeNode <K, V> node) { node.MakeNodeRed(); WeightedRedBlackTreeNode <K, V> parent = node.Parent; while (node != Root && parent.IsRed()) { if (parent == parent.Parent.Left) { WeightedRedBlackTreeNode <K, V> uncle = parent.Parent.Right; if (uncle.IsRed()) { parent.MakeNodeBlack(); uncle.MakeNodeBlack(); parent.Parent.MakeNodeRed(); node = parent.Parent; parent = node.Parent; } else { if (node == parent.Right) { node = parent; RotateLeft(node); parent = node.Parent; } parent.MakeNodeBlack(); parent.Parent.MakeNodeRed(); RotateRight(parent.Parent); parent = node.Parent; } } else { WeightedRedBlackTreeNode <K, V> uncle = parent.Parent.Left; if (uncle.IsRed()) { parent.MakeNodeBlack(); uncle.MakeNodeBlack(); parent.Parent.MakeNodeRed(); node = parent.Parent; parent = node.Parent; } else { if (node == parent.Left) { node = parent; RotateRight(node); parent = node.Parent; } parent.MakeNodeBlack(); parent.Parent.MakeNodeRed(); RotateLeft(parent.Parent); parent = node.Parent; } } } Root.MakeNodeBlack(); }