// Uncomment this to enable the following debugging aids: // LeftLeaningRedBlackTree.HtmlFragment // LeftLeaningRedBlackTree.EntityView.HtmlFragment // LeftLeaningRedBlackTree.AssertInvariants // #define DEBUGGING using System; using System.Collections.Generic; using System.Diagnostics; /// /// Implements a left-leaning red-black tree. /// /// /// Based on the research paper "Left-leaning Red-Black Trees" /// by Robert Sedgewick. More information available at: /// http://www.cs.princeton.edu/~rs/talks/LLRB/RedBlack.pdf /// http://www.cs.princeton.edu/~rs/talks/LLRB/08Penn.pdf /// /// Type of keys. /// Type of values. public class LeftLeaningRedBlackTree { /// /// Stores the key comparison function. /// private Comparison _keyComparison; /// /// Stores the value comparison function. /// private Comparison _valueComparison; /// /// Stores the root entityView of the tree. /// private EntityView _rootEntityView; /// /// Represents a entityView of the tree. /// /// /// Using fields instead of properties drops execution time by about 40%. /// [DebuggerDisplay("Key={Key}, Value={Value}, Siblings={Siblings}")] private class EntityView { /// /// Gets or sets the entityView's key. /// public TKey Key; /// /// Gets or sets the entityView's value. /// public TValue Value; /// /// Gets or sets the left entityView. /// public EntityView Left; /// /// Gets or sets the right entityView. /// public EntityView Right; /// /// Gets or sets the color of the entityView. /// public bool IsBlack; /// /// Gets or sets the number of "siblings" (entityViews with the same key/value). /// public int Siblings; #if DEBUGGING /// /// Gets an HTML fragment representing the entityView and its children. /// public string HtmlFragment { get { return "" + "" + "" + "" + "" + "" + "" + "" + "
" + Key + ", " + Value + " [" + Siblings + "]
" + (null != Left ? Left.HtmlFragment : "[null]") + "" + (null != Right ? Right.HtmlFragment : "[null]") + "
"; } } #endif } /// /// Initializes a new instance of the LeftLeaningRedBlackTree class implementing a normal dictionary. /// /// The key comparison function. public LeftLeaningRedBlackTree(Comparison keyComparison) { if (null == keyComparison) { throw new ArgumentNullException("keyComparison"); } _keyComparison = keyComparison; } /// /// Initializes a new instance of the LeftLeaningRedBlackTree class implementing an ordered multi-dictionary. /// /// The key comparison function. /// The value comparison function. public LeftLeaningRedBlackTree(Comparison keyComparison, Comparison valueComparison) : this(keyComparison) { if (null == valueComparison) { throw new ArgumentNullException("valueComparison"); } _valueComparison = valueComparison; } /// /// Gets a value indicating whether the tree is acting as an ordered multi-dictionary. /// private bool IsMultiDictionary { get { return null != _valueComparison; } } /// /// Adds a key/value pair to the tree. /// /// Key to add. /// Value to add. public void Add(TKey key, TValue value) { _rootEntityView = Add(_rootEntityView, key, value); _rootEntityView.IsBlack = true; #if DEBUGGING AssertInvariants(); #endif } /// /// Removes a key (and its associated value) from a normal (non-multi) dictionary. /// /// Key to remove. /// True if key present and removed. public bool Remove(TKey key) { if (IsMultiDictionary) { throw new InvalidOperationException("Remove is only supported when acting as a normal (non-multi) dictionary."); } return Remove(key, default(TValue)); } /// /// Removes a key/value pair from the tree. /// /// Key to remove. /// Value to remove. /// True if key/value present and removed. public bool Remove(TKey key, TValue value) { int initialCount = Count; if (null != _rootEntityView) { _rootEntityView = Remove(_rootEntityView, key, value); if (null != _rootEntityView) { _rootEntityView.IsBlack = true; } } #if DEBUGGING AssertInvariants(); #endif return initialCount != Count; } /// /// Removes all entityViews in the tree. /// public void Clear() { _rootEntityView = null; Count = 0; #if DEBUGGING AssertInvariants(); #endif } /// /// Gets a sorted list of keys in the tree. /// /// Sorted list of keys. public IEnumerable GetKeys() { TKey lastKey = default(TKey); bool lastKeyValid = false; return Traverse( _rootEntityView, n => !lastKeyValid || !object.Equals(lastKey, n.Key), n => { lastKey = n.Key; lastKeyValid = true; return lastKey; }); } /// /// Gets the value associated with the specified key in a normal (non-multi) dictionary. /// /// Specified key. /// Value associated with the specified key. public TValue GetValueForKey(TKey key) { if (IsMultiDictionary) { throw new InvalidOperationException("GetValueForKey is only supported when acting as a normal (non-multi) dictionary."); } EntityView entityView = GetEntityViewForKey(key); if (null != entityView) { return entityView.Value; } else { throw new KeyNotFoundException(); } } /// /// Gets a sequence of the values associated with the specified key. /// /// Specified key. /// Sequence of values. public IEnumerable GetValuesForKey(TKey key) { return Traverse(GetEntityViewForKey(key), n => 0 == _keyComparison(n.Key, key), n => n.Value); } /// /// Gets a sequence of all the values in the tree. /// /// Sequence of all values. public IEnumerable GetValuesForAllKeys() { return Traverse(_rootEntityView, n => true, n => n.Value); } /// /// Gets the count of key/value pairs in the tree. /// public int Count { get; private set; } /// /// Gets the minimum key in the tree. /// public TKey MinimumKey { get { return GetExtreme(_rootEntityView, n => n.Left, n => n.Key); } } /// /// Gets the maximum key in the tree. /// public TKey MaximumKey { get { return GetExtreme(_rootEntityView, n => n.Right, n => n.Key); } } /// /// Returns true if the specified entityView is red. /// /// Specified entityView. /// True if specified entityView is red. private static bool IsRed(EntityView entityView) { if (null == entityView) { // "Virtual" leaf entityViews are always black return false; } return !entityView.IsBlack; } /// /// Adds the specified key/value pair below the specified root entityView. /// /// Specified entityView. /// Key to add. /// Value to add. /// New root entityView. private EntityView Add(EntityView entityView, TKey key, TValue value) { if (null == entityView) { // Insert new entityView Count++; return new EntityView { Key = key, Value = value }; } if (IsRed(entityView.Left) && IsRed(entityView.Right)) { // Split entityView with two red children FlipColor(entityView); } // Find right place for new entityView int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); if (comparisonResult < 0) { entityView.Left = Add(entityView.Left, key, value); } else if (0 < comparisonResult) { entityView.Right = Add(entityView.Right, key, value); } else { if (IsMultiDictionary) { // Store the presence of a "duplicate" entityView entityView.Siblings++; Count++; } else { // Replace the value of the existing entityView entityView.Value = value; } } if (IsRed(entityView.Right)) { // Rotate to prevent red entityView on right entityView = RotateLeft(entityView); } if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { // Rotate to prevent consecutive red entityViews entityView = RotateRight(entityView); } return entityView; } /// /// Removes the specified key/value pair from below the specified entityView. /// /// Specified entityView. /// Key to remove. /// Value to remove. /// True if key/value present and removed. private EntityView Remove(EntityView entityView, TKey key, TValue value) { int comparisonResult = KeyAndValueComparison(key, value, entityView.Key, entityView.Value); if (comparisonResult < 0) { // * Continue search if left is present if (null != entityView.Left) { if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { // Move a red entityView over entityView = MoveRedLeft(entityView); } // Remove from left entityView.Left = Remove(entityView.Left, key, value); } } else { if (IsRed(entityView.Left)) { // Flip a 3 entityView or unbalance a 4 entityView entityView = RotateRight(entityView); } if ((0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) && (null == entityView.Right)) { // Remove leaf entityView Debug.Assert(null == entityView.Left, "About to remove an extra entityView."); Count--; if (0 < entityView.Siblings) { // Record the removal of the "duplicate" entityView Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); entityView.Siblings--; return entityView; } else { // Leaf entityView is gone return null; } } // * Continue search if right is present if (null != entityView.Right) { if (!IsRed(entityView.Right) && !IsRed(entityView.Right.Left)) { // Move a red entityView over entityView = MoveRedRight(entityView); } if (0 == KeyAndValueComparison(key, value, entityView.Key, entityView.Value)) { // Remove leaf entityView Count--; if (0 < entityView.Siblings) { // Record the removal of the "duplicate" entityView Debug.Assert(IsMultiDictionary, "Should not have siblings if tree is not a multi-dictionary."); entityView.Siblings--; } else { // Find the smallest entityView on the right, swap, and remove it EntityView m = GetExtreme(entityView.Right, n => n.Left, n => n); entityView.Key = m.Key; entityView.Value = m.Value; entityView.Siblings = m.Siblings; entityView.Right = DeleteMinimum(entityView.Right); } } else { // Remove from right entityView.Right = Remove(entityView.Right, key, value); } } } // Maintain invariants return FixUp(entityView); } /// /// Flip the colors of the specified entityView and its direct children. /// /// Specified entityView. private static void FlipColor(EntityView entityView) { entityView.IsBlack = !entityView.IsBlack; entityView.Left.IsBlack = !entityView.Left.IsBlack; entityView.Right.IsBlack = !entityView.Right.IsBlack; } /// /// Rotate the specified entityView "left". /// /// Specified entityView. /// New root entityView. private static EntityView RotateLeft(EntityView entityView) { EntityView x = entityView.Right; entityView.Right = x.Left; x.Left = entityView; x.IsBlack = entityView.IsBlack; entityView.IsBlack = false; return x; } /// /// Rotate the specified entityView "right". /// /// Specified entityView. /// New root entityView. private static EntityView RotateRight(EntityView entityView) { EntityView x = entityView.Left; entityView.Left = x.Right; x.Right = entityView; x.IsBlack = entityView.IsBlack; entityView.IsBlack = false; return x; } /// /// Moves a red entityView from the right child to the left child. /// /// Parent entityView. /// New root entityView. private static EntityView MoveRedLeft(EntityView entityView) { FlipColor(entityView); if (IsRed(entityView.Right.Left)) { entityView.Right = RotateRight(entityView.Right); entityView = RotateLeft(entityView); FlipColor(entityView); // * Avoid creating right-leaning entityViews if (IsRed(entityView.Right.Right)) { entityView.Right = RotateLeft(entityView.Right); } } return entityView; } /// /// Moves a red entityView from the left child to the right child. /// /// Parent entityView. /// New root entityView. private static EntityView MoveRedRight(EntityView entityView) { FlipColor(entityView); if (IsRed(entityView.Left.Left)) { entityView = RotateRight(entityView); FlipColor(entityView); } return entityView; } /// /// Deletes the minimum entityView under the specified entityView. /// /// Specified entityView. /// New root entityView. private EntityView DeleteMinimum(EntityView entityView) { if (null == entityView.Left) { // Nothing to do return null; } if (!IsRed(entityView.Left) && !IsRed(entityView.Left.Left)) { // Move red entityView left entityView = MoveRedLeft(entityView); } // Recursively delete entityView.Left = DeleteMinimum(entityView.Left); // Maintain invariants return FixUp(entityView); } /// /// Maintains invariants by adjusting the specified entityViews children. /// /// Specified entityView. /// New root entityView. private static EntityView FixUp(EntityView entityView) { if (IsRed(entityView.Right)) { // Avoid right-leaning entityView entityView = RotateLeft(entityView); } if (IsRed(entityView.Left) && IsRed(entityView.Left.Left)) { // Balance 4-entityView entityView = RotateRight(entityView); } if (IsRed(entityView.Left) && IsRed(entityView.Right)) { // Push red up FlipColor(entityView); } // * Avoid leaving behind right-leaning entityViews if ((null != entityView.Left) && IsRed(entityView.Left.Right) && !IsRed(entityView.Left.Left)) { entityView.Left = RotateLeft(entityView.Left); if (IsRed(entityView.Left)) { // Balance 4-entityView entityView = RotateRight(entityView); } } return entityView; } /// /// Gets the (first) entityView corresponding to the specified key. /// /// Key to search for. /// Corresponding entityView or null if none found. private EntityView GetEntityViewForKey(TKey key) { // Initialize EntityView entityView = _rootEntityView; while (null != entityView) { // Compare keys and go left/right int comparisonResult = _keyComparison(key, entityView.Key); if (comparisonResult < 0) { entityView = entityView.Left; } else if (0 < comparisonResult) { entityView = entityView.Right; } else { // Match; return entityView return entityView; } } // No match found return null; } /// /// Gets an extreme (ex: minimum/maximum) value. /// /// Type of value. /// EntityView to start from. /// Successor function. /// Selector function. /// Extreme value. private static T GetExtreme(EntityView entityView, Func successor, Func selector) { // Initialize T extreme = default(T); EntityView current = entityView; while (null != current) { // Go to extreme extreme = selector(current); current = successor(current); } return extreme; } /// /// Traverses a subset of the sequence of entityViews in order and selects the specified entityViews. /// /// Type of elements. /// Starting entityView. /// Condition method. /// Selector method. /// Sequence of selected entityViews. private IEnumerable Traverse(EntityView entityView, Func condition, Func selector) { // Create a stack to avoid recursion Stack stack = new Stack(); EntityView current = entityView; while (null != current) { if (null != current.Left) { // Save current state and go left stack.Push(current); current = current.Left; } else { do { for (int i = 0; i <= current.Siblings; i++) { // Select current entityView if relevant if (condition(current)) { yield return selector(current); } } // Go right - or up if nothing to the right current = current.Right; } while ((null == current) && (0 < stack.Count) && (null != (current = stack.Pop()))); } } } /// /// Compares the specified keys (primary) and values (secondary). /// /// The left key. /// The left value. /// The right key. /// The right value. /// CompareTo-style results: -1 if left is less, 0 if equal, and 1 if greater than right. private int KeyAndValueComparison(TKey leftKey, TValue leftValue, TKey rightKey, TValue rightValue) { // Compare keys int comparisonResult = _keyComparison(leftKey, rightKey); if ((0 == comparisonResult) && (null != _valueComparison)) { // Keys match; compare values comparisonResult = _valueComparison(leftValue, rightValue); } return comparisonResult; } #if DEBUGGING /// /// Asserts that tree invariants are not violated. /// private void AssertInvariants() { // Root is black Debug.Assert((null == _rootEntityView) || _rootEntityView.IsBlack, "Root is not black"); // Every path contains the same number of black entityViews Dictionary parents = new Dictionary.EntityView, LeftLeaningRedBlackTree.EntityView>(); foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { if (null != entityView.Left) { parents[entityView.Left] = entityView; } if (null != entityView.Right) { parents[entityView.Right] = entityView; } } if (null != _rootEntityView) { parents[_rootEntityView] = null; } int treeCount = -1; foreach (EntityView entityView in Traverse(_rootEntityView, n => (null == n.Left) || (null == n.Right), n => n)) { int pathCount = 0; EntityView current = entityView; while (null != current) { if (current.IsBlack) { pathCount++; } current = parents[current]; } Debug.Assert((-1 == treeCount) || (pathCount == treeCount), "Not all paths have the same number of black entityViews."); treeCount = pathCount; } // Verify entityView properties... foreach (EntityView entityView in Traverse(_rootEntityView, n => true, n => n)) { // Left entityView is less if (null != entityView.Left) { Debug.Assert(0 > KeyAndValueComparison(entityView.Left.Key, entityView.Left.Value, entityView.Key, entityView.Value), "Left entityView is greater than its parent."); } // Right entityView is greater if (null != entityView.Right) { Debug.Assert(0 < KeyAndValueComparison(entityView.Right.Key, entityView.Right.Value, entityView.Key, entityView.Value), "Right entityView is less than its parent."); } // Both children of a red entityView are black Debug.Assert(!IsRed(entityView) || (!IsRed(entityView.Left) && !IsRed(entityView.Right)), "Red entityView has a red child."); // Always left-leaning Debug.Assert(!IsRed(entityView.Right) || IsRed(entityView.Left), "EntityView is not left-leaning."); // No consecutive reds (subset of previous rule) //Debug.Assert(!(IsRed(entityView) && IsRed(entityView.Left))); } } /// /// Gets an HTML fragment representing the tree. /// public string HtmlDocument { get { return "" + "" + (null != _rootEntityView ? _rootEntityView.HtmlFragment : "[null]") + "" + ""; } } #endif }