/*
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
}
}