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