/// <summary>Adds a node to the tree.</summary> /// <param name="data">Data to be contained at the new node location.</param> /// <param name="key">Key used for comparison and lookup.</param> /// <exception cref="ArgumentNullException">Thrown if data is null.</exception> /// <exception cref="ArgumentException">Thrown if data already exists in the tree.</exception> /// <exception cref="ArgumentException">Thrown if key is not of type IComparable.</exception> public override void Add(TKey key, TValue data) { if (key == null) { throw new ArgumentNullException("key"); } Node <TKey, TValue> parent = null; RedBlackNode <TKey, TValue> .Add(ref Root, ref parent, key, data); Count++; // Do a Debug Sanity Check on the Tree if (Root != null) { Root.Check(); } }
/// <summary>Adds the given key and value to the tree at the current node.</summary> /// <param name="root">Node to add key/value pair to.</param> /// <param name="parent">Parent node of root.</param> /// <param name="key">Key used to index the value.</param> /// <param name="value">Value to add to the node</param> public static void Add(ref Node <TKey, TValue> root, ref Node <TKey, TValue> parent, TKey key, TValue value) { // See if the tree is empty if (root == null) { // Insert new node here. If parent is null this is the first node so it should be black - // otherwise make it red. root = new RedBlackNode <TKey, TValue>(key, value) { Color = (parent == null) ? NodeColor.Black : NodeColor.Red }; return; } // Compare items and determine which direction to search // Make sure that nResult is between -1 and 1 int nResult = key.CompareTo(root.Key); uint dir = (nResult < 0) ? LEFT : RIGHT; if (nResult == 0) { throw new ArgumentException("Attempting to add duplicate item to the tree. The items has a value of " + key.ToString(), "data"); } else { // Insert into "dir" subtree RedBlackNode <TKey, TValue> rbRoot = (RedBlackNode <TKey, TValue>)root; Add(ref rbRoot.Nodes[dir], ref root, key, value); // Check for red-property violation with child rbRoot = (RedBlackNode <TKey, TValue>)root; RedBlackNode <TKey, TValue> rbChild = (RedBlackNode <TKey, TValue>)root[dir]; if ((rbRoot.Color == NodeColor.Red) && (rbChild.Color == NodeColor.Red)) { FixRedViolation(ref parent, ref root, dir); } } }
/// <summary>Removes the node containing this data from the tree.</summary> /// <param name="key">Value to remove from the tree.</param> /// <exception cref="ArgumentNullException">Thrown if data is null.</exception> /// <exception cref="ArgumentException">Thrown if key is not of type IComparable.</exception> /// <remarks>If data does not exist in the tree, then the tree remains unchanged. No exception is thrown.</remarks> public override bool Remove(TKey key) { if (key == null) { throw new ArgumentNullException("key"); } bool blackDecrease = false; bool bFound = false; if (RedBlackNode <TKey, TValue> .Remove(ref Root, key, ref blackDecrease, Node <TKey, TValue> .CompType.EQ_CMP) != null) { Count--; bFound = true; } // Do a Debug Sanity Check on the Tree if (Root != null) { Root.Check(); } return(bFound); }
private static bool FixBlackViolation(ref Node <TKey, TValue> root, uint dir) { bool propagated = false; // Initialize the return value // "dir" is the direction that just became deficient, the other // direction is the side that wasnt deleted from. uint otherDir = Opposite(dir); // Get the deficient subtree (if its exists) and its sibling RedBlackNode <TKey, TValue> child = (RedBlackNode <TKey, TValue>)root[dir]; RedBlackNode <TKey, TValue> sibling = (RedBlackNode <TKey, TValue>)root[otherDir]; if (GetColor(child) == NodeColor.Red) { // Increase the black height of this entire subtree by // simply making the child black. In theory - this routine // will never be called if the child is red. child.Color = NodeColor.Black; } else if (GetColor(sibling) == NodeColor.Black) { // Need to know if the parent is red or not. If it is, then // any rotated result needs to have a red-root (and root will // need to change to black), otherwise any rotated result will // have a black root. bool blackParent = (GetColor(root) == NodeColor.Black); if (!blackParent) { ((RedBlackNode <TKey, TValue>)root).Color = NodeColor.Black; } // Now look at the color of the sibling's children if (GetColor(sibling[dir]) == NodeColor.Red) { // Need to change the color of this subtree if the parent is black if (blackParent) { ((RedBlackNode <TKey, TValue>)sibling[dir]).Color = NodeColor.Black; } // Now rotate twice to make this subtree the new root RotateTwice(ref root, dir); } else if (GetColor(sibling[otherDir]) == NodeColor.Red) { // Need to change the color of this subtree ((RedBlackNode <TKey, TValue>)sibling[otherDir]).Color = NodeColor.Black; // If the root is red then exchange its color with the sibling if (!blackParent) { sibling.Color = NodeColor.Red; } // Now rotate once to make the sibling the new root RotateOnce(ref root, dir); } else { // Make the sibling red sibling.Color = NodeColor.Red; // If the root was black we have fixed the black-property // violation at this level by shortening the black height of // the "dir" subtree, hence the problem has been propagated // up to the next higher level. propagated = blackParent; } } else { // First, perform a single rotation and flip the color of the // sibling and its "dir" subtree. sibling.Color = NodeColor.Black; ((RedBlackNode <TKey, TValue>)sibling[dir]).Color = NodeColor.Red; RotateOnce(ref root, dir); // Now check for a red-property violation with the sibling's // subtree (which after the rotation, is now in a different // position). Note that the sibling's former subtree is the // "nephew" or "niece" of the child. RedBlackNode <TKey, TValue> rbRoot = (RedBlackNode <TKey, TValue>)root; RedBlackNode <TKey, TValue> tempNode = (RedBlackNode <TKey, TValue>)root[dir]; Node <TKey, TValue> niece = root[dir][otherDir]; if ((GetColor(niece[dir]) == NodeColor.Red) && (GetColor(niece[otherDir]) == NodeColor.Red)) { // change the color of the niece ((RedBlackNode <TKey, TValue>)niece).Color = NodeColor.Black; // No child, need an additional rotation // (this time a double) if (child == null) { RotateTwice(ref rbRoot.Nodes[dir], dir); } } else if (GetColor(niece[dir]) == NodeColor.Red) { FixRedViolation(ref rbRoot.Nodes[dir], ref tempNode.Nodes[otherDir], dir); } else if (GetColor(niece[otherDir]) == NodeColor.Red) { FixRedViolation(ref rbRoot.Nodes[dir], ref tempNode.Nodes[otherDir], otherDir); } } return(propagated); }