/* Copyright 2007-2013 The NGenerics Team (https://github.com/ngenerics/ngenerics/wiki/Team) This program is licensed under the GNU Lesser General Public License (LGPL). You should have received a copy of the license along with the source code. If not, an online copy of the license can be found at http://www.gnu.org/copyleft/lesser.html. */ /* * The insertion and deletion code is based on the code found at http://eternallyconfuzzled.com/tuts/redblack.htm. * It's an excellent tutorial - if you want to understand Red Black trees, look there first. */ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; namespace NGenerics.DataStructures.Trees { /// /// An implementation of a Red-Black tree. /// /// The type of element to keep in the tree. [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] //[Serializable] public class RedBlackTree : BinarySearchTreeBase { #region Construction /// public RedBlackTree() { // Do nothing - the default Comparer will be used by the base class. } /// public RedBlackTree(IComparer comparer) : base(comparer) { // Do nothing else. } /// public RedBlackTree(Comparison comparison) : base(comparison) { // Do nothing else. } #endregion #region Public Members /// /// Adds an element with the provided key and value to the . /// /// The item. protected override void AddItem(T item) { #region Validation if (Equals(item, null)) { throw new ArgumentNullException("item"); } #endregion var root = (RedBlackTreeNode)Tree; var newRoot = InsertNode(root, item); newRoot.Color = NodeColor.Black; Tree = newRoot; } /// /// Removes the element with the specified key from the . /// /// The item to remove. /// /// true if the element is successfully removed; otherwise, false. This method also returns false if key was not found in the original . /// /// protected override bool RemoveItem(T item) { if (Tree != null) { var startNode = new RedBlackTreeNode(default(T)); var childNode = startNode; startNode.Right = (RedBlackTreeNode)Tree; RedBlackTreeNode parent = null; RedBlackTreeNode foundNode = null; var direction = true; while (childNode[direction] != null) { var lastDirection = direction; var grandParent = parent; parent = childNode; childNode = childNode[direction]; var comparisonValue = Comparer.Compare(childNode.Data, item); if (comparisonValue == 0) { foundNode = childNode; } direction = comparisonValue < 0; if ((IsBlack(childNode)) && (IsBlack(childNode[direction]))) { if (IsRed(childNode[!direction])) { parent = parent[lastDirection] = SingleRotation(childNode, direction); } else if (IsBlack(childNode[direction])) { var sibling = parent[!lastDirection]; if (sibling != null) { if ((IsBlack(sibling.Left)) && (IsBlack(sibling.Right))) { parent.Color = NodeColor.Black; sibling.Color = NodeColor.Red; childNode.Color = NodeColor.Red; } else { var parentDirection = grandParent.Right == parent; if (IsRed(sibling[lastDirection])) { grandParent[parentDirection] = DoubleRotation(parent, lastDirection); } else if (IsRed(sibling[!lastDirection])) { grandParent[parentDirection] = SingleRotation(parent, lastDirection); } childNode.Color = grandParent[parentDirection].Color = NodeColor.Red; grandParent[parentDirection].Left.Color = NodeColor.Black; grandParent[parentDirection].Right.Color = NodeColor.Black; } } } } } if (foundNode != null) { foundNode.Data = childNode.Data; parent[parent.Right == childNode] = childNode[childNode.Left == null]; } Tree = startNode.Right; if (Tree != null) { ((RedBlackTreeNode)Tree).Color = NodeColor.Black; } if (foundNode != null) { return true; } } return false; } #endregion #region Private Members /// /// Determines whether the specified node is red. /// /// The node. /// /// true if the specified node is red; otherwise, false. /// private static bool IsRed(RedBlackTreeNode node) { return (node != null) && (node.Color == NodeColor.Red); } /// /// Determines whether the specified node is black. /// /// The node. /// /// true if the specified node is black; otherwise, false. /// private static bool IsBlack(RedBlackTreeNode node) { return (node == null) || (node.Color == NodeColor.Black); } /// /// A recursive implementation of insertion of a node into the tree. /// /// The start node. /// The item. /// The node created in the insertion. private RedBlackTreeNode InsertNode(RedBlackTreeNode node, T item) { if (node == null) { node = new RedBlackTreeNode(item); } else if (Comparer.Compare(item, node.Data) != 0) { var direction = Comparer.Compare(node.Data, item) < 0; node[direction] = InsertNode(node[direction], item); if (IsRed(node[direction])) { if (IsRed(node[!direction])) { node.Color = NodeColor.Red; node.Left.Color = NodeColor.Black; node.Right.Color = NodeColor.Black; } else { if (IsRed(node[direction][direction])) { node = SingleRotation(node, !direction); } else if (IsRed(node[direction][!direction])) { node = DoubleRotation(node, !direction); } } } } else { throw new ArgumentException(alreadyContainedInTheTree); } return node; } /// /// Perform a single rotation on the node provided.. /// /// The node on which to focus the rotation. /// The direction of the rotation. If direction is equal to true, a right rotation is performed. Other wise, a left rotation. /// The new root of the cluster. private static RedBlackTreeNode SingleRotation(RedBlackTreeNode node, bool direction) { var childSibling = node[!direction]; node[!direction] = childSibling[direction]; childSibling[direction] = node; node.Color = NodeColor.Red; childSibling.Color = NodeColor.Black; return childSibling; } /// /// Perform a double rotation on the node provided.. /// /// The node on which to focus the rotation. /// The direction of the rotation. If direction is equal to true, a right rotation is performed. Other wise, a left rotation. /// The new root of the cluster. private static RedBlackTreeNode DoubleRotation(RedBlackTreeNode node, bool direction) { node[!direction] = SingleRotation(node[!direction], !direction); return SingleRotation(node, direction); } #endregion } }