/Raven.Database/Storage/Managed/Munin/Tree/AVLTree.cs
http://github.com/ayende/ravendb · C# · 456 lines · 390 code · 50 blank · 16 comment · 56 complexity · d8bc1b8ab083790cc23d2ce95cf9b5ba MD5 · raw file
- //-----------------------------------------------------------------------
- // <copyright file="AVLTree.cs" company="Hibernating Rhinos LTD">
- // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
- // </copyright>
- //-----------------------------------------------------------------------
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Raven.Json.Linq;
- namespace Raven.Munin.Tree
- {
- // Code originated from
- // http://blogs.msdn.com/b/ericlippert/archive/2008/01/21/immutability-in-c-part-nine-academic-plus-my-avl-tree-implementation.aspx
- public sealed class AVLTree<TKey, TValue> : IBinarySearchTree<TKey, TValue>
- {
- private readonly int height;
- public override string ToString()
- {
- return string.Format("Key: {0}, Value: {1}, Count: {2}", theKey, theValue, Count);
- }
- public RavenJObject ToJObject()
- {
- return new RavenJObject
- {
- {"key", RavenJToken.FromObject(theKey)},
- {"value", RavenJToken.FromObject(theValue)},
- {"left", Left.ToJObject()},
- {"right", Right.ToJObject()}
- };
- }
- private readonly IComparer<TKey> comparer;
- private readonly Func<TKey, TKey> deepCopyKey;
- private readonly Func<TValue, TValue> deepCopyValue;
- private readonly TKey theKey;
- private readonly IBinarySearchTree<TKey, TValue> left;
- private readonly IBinarySearchTree<TKey, TValue> right;
- private readonly TValue theValue;
- public int Count { get; private set; }
- internal AVLTree(
- IComparer<TKey> comparer,
- Func<TKey, TKey> deepCopyKey,
- Func<TValue, TValue> deepCopyValue,
- TKey key,
- TValue value,
- IBinarySearchTree<TKey, TValue> left,
- IBinarySearchTree<TKey, TValue> right)
- {
- this.comparer = comparer;
- this.deepCopyKey = deepCopyKey;
- this.deepCopyValue = deepCopyValue;
- this.theKey = key;
- this.theValue = value;
- this.left = left;
- this.right = right;
- height = 1 + Math.Max(Height(left), Height(right));
- Count = 1 + Left.Count + Right.Count;
- }
- // IBinaryTree
- #region IBinarySearchTree<TKey,TValue> Members
- public IComparer<TKey> Comparer
- {
- get { return comparer; }
- }
- public bool IsEmpty
- {
- get { return false; }
- }
- public TValue Value
- {
- get { return deepCopyValue(theValue); }
- }
- public IBinarySearchTree<TKey, TValue> LeftMost
- {
- get
- {
- if(Left.IsEmpty)
- return this;
- var current = Left;
- while (current.Left.IsEmpty == false)
- current = current.Left;
- return current.LeftMost;
- }
- }
- public IBinarySearchTree<TKey, TValue> RightMost
- {
- get
- {
- if (Right.IsEmpty)
- return this;
- var current = Right;
- while (current.Right.IsEmpty == false)
- current = current.Right;
- return current.RightMost;
- }
- }
- // IBinarySearchTree
- public IBinarySearchTree<TKey, TValue> Left
- {
- get { return left; }
- }
- public IBinarySearchTree<TKey, TValue> Right
- {
- get { return right; }
- }
- public IBinarySearchTree<TKey, TValue> LocateNearest(TKey key, Predicate<TValue> isMatch)
- {
- if (isMatch(Value))
- return this;
- int compare = comparer.Compare(key, theKey);
- if (compare == 0)
- return this;
- if (compare > 0)
- return Right.LocateNearest(key, isMatch);
- return Left.LocateNearest(key, isMatch);
- }
- public IBinarySearchTree<TKey, TValue> Search(TKey key)
- {
- int compare = comparer.Compare(key, theKey);
- if (compare == 0)
- return this;
- if (compare > 0)
- return Right.Search(key);
- return Left.Search(key);
- }
- public IEnumerable<TValue> GreaterThan(TKey gtKey)
- {
- int compare = comparer.Compare(theKey, gtKey);
- if (compare <= 0)
- {
- foreach (var value in Right.GreaterThan(gtKey))
- {
- yield return value;
- }
- yield break;
- }
- foreach (var value in Left.GreaterThan(gtKey))
- {
- yield return value;
- }
- yield return Value;
- foreach (var value in Right.GreaterThan(gtKey))
- {
- yield return value;
- }
- }
- public IEnumerable<TValue> LessThan(TKey ltKey)
- {
- int compare = comparer.Compare(theKey, ltKey);
- if(compare < 0)
- {
- foreach (var value in Right.LessThan(ltKey))
- {
- yield return value;
- }
- }
- if (compare <= 0)
- yield return Value;
- foreach (var value in Left.LessThan(ltKey))
- {
- yield return value;
- }
- }
- public IEnumerable<TValue> LessThanOrEqual(TKey ltKey)
- {
- int compare = comparer.Compare(theKey, ltKey);
- if (compare < 0)
- {
- foreach (var value in Right.LessThanOrEqual(ltKey))
- {
- yield return value;
- }
- }
- if (compare <= 0)
- {
- yield return Value;
- }
- foreach (var value in Left.LessThanOrEqual(ltKey))
- {
- yield return value;
- }
- }
- public IEnumerable<TValue> GreaterThanOrEqual(TKey gteKey)
- {
- int compare = comparer.Compare(theKey, gteKey);
- if (compare < 0)
- {
- foreach (var value in Right.GreaterThanOrEqual(gteKey))
- {
- yield return value;
- }
- yield break;
- }
- foreach (var value in Left.GreaterThanOrEqual(gteKey))
- {
- yield return value;
- }
- yield return Value;
- foreach (var value in Right.GreaterThanOrEqual(gteKey))
- {
- yield return value;
- }
- }
- public TKey Key
- {
- get { return deepCopyKey(theKey); }
- }
- public IBinarySearchTree<TKey, TValue> Add(TKey key, TValue value)
- {
- AVLTree<TKey, TValue> result;
- var compare = comparer.Compare(key, theKey);
- if(compare == 0)
- return new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, key, value, Left, Right);
-
- if (compare > 0)
- result = new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, theKey, theValue, Left, Right.Add(key, value));
- else
- result = new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, theKey, theValue, Left.Add(key, value), Right);
-
- return MakeBalanced(result);
- }
- public IBinarySearchTree<TKey, TValue> AddOrUpdate(TKey key, TValue value, Func<TKey, TValue, TValue> updateValueFactory)
- {
- AVLTree<TKey, TValue> result;
- var compare = comparer.Compare(key, theKey);
- if (compare > 0)
- result = new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, theKey, theValue, Left, Right.AddOrUpdate(key, value, updateValueFactory));
- else if(compare < 0)
- result = new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, theKey, theValue, Left.AddOrUpdate(key, value, updateValueFactory), Right);
- else
- {
- var newValue = updateValueFactory(key, theValue);
- result = new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, key, newValue, Left, Right);
- }
- return MakeBalanced(result);
- }
- public IBinarySearchTree<TKey, TValue> TryRemove(TKey key, out bool removed, out TValue value)
- {
- IBinarySearchTree<TKey, TValue> result;
- int compare = comparer.Compare(key, theKey);
- if (compare == 0)
- {
- removed = true;
- value = theValue;
- // We have a match. If this is a leaf, just remove it
- // by returning Empty. If we have only one child,
- // replace the node with the child.
- if (Right.IsEmpty && Left.IsEmpty)
- result = new EmptyAVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue);
- else if (Right.IsEmpty && !Left.IsEmpty)
- result = Left;
- else if (!Right.IsEmpty && Left.IsEmpty)
- result = Right;
- else
- {
- // We have two children. Remove the next-highest node and replace
- // this node with it.
- IBinarySearchTree<TKey, TValue> successor = Right;
- while (!successor.Left.IsEmpty)
- successor = successor.Left;
- bool ignoredBool;
- TValue ignoredValue;
- result = new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, successor.Key, successor.Value, Left, Right.TryRemove(successor.Key, out ignoredBool, out ignoredValue));
- }
- }
- else if (compare < 0)
- result = new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, theKey, theValue, Left.TryRemove(key, out removed, out value), Right);
- else
- result = new AVLTree<TKey, TValue>(comparer, deepCopyKey, deepCopyValue, theKey, theValue, Left, Right.TryRemove(key, out removed, out value));
- return MakeBalanced(result);
- }
- // IMap
- public bool Contains(TKey key)
- {
- return !Search(key).IsEmpty;
- }
- public bool TryGetValue(TKey key, out TValue value)
- {
- value = default(TValue);
- IBinarySearchTree<TKey, TValue> tree = Search(key);
- if (tree.IsEmpty)
- return false;
- value = tree.Value;
- return true;
- }
- public IEnumerable<TKey> KeysInOrder
- {
- get { return from t in EnumerateInOrder() select t.Key; }
- }
- public IEnumerable<TKey> KeysInReverseOrder
- {
- get { return from t in EnumerateInReverseOrder() select t.Key; }
- }
- public IEnumerable<TValue> ValuesInOrder
- {
- get { return from t in EnumerateInOrder() select t.Value; }
- }
- public IEnumerable<TValue> ValuesInReverseOrder
- {
- get { return from t in EnumerateInReverseOrder() select t.Value; }
- }
- public IEnumerable<KeyValuePair<TKey, TValue>> Pairs
- {
- get { return from t in EnumerateInOrder() select new KeyValuePair<TKey, TValue>(t.Key, t.Value); }
- }
- #endregion
- private IEnumerable<IBinarySearchTree<TKey, TValue>> EnumerateInOrder()
- {
- var stack = Stack<IBinarySearchTree<TKey, TValue>>.Empty;
- for (IBinarySearchTree<TKey, TValue> current = this; !current.IsEmpty || !stack.IsEmpty; current = current.Right)
- {
- while (!current.IsEmpty)
- {
- stack = stack.Push(current);
- current = current.Left;
- }
- current = stack.Peek();
- stack = stack.Pop();
- yield return current;
- }
- }
- private IEnumerable<IBinarySearchTree<TKey, TValue>> EnumerateInReverseOrder()
- {
- var stack = Stack<IBinarySearchTree<TKey, TValue>>.Empty;
- for (IBinarySearchTree<TKey, TValue> current = this; !current.IsEmpty || !stack.IsEmpty; current = current.Left)
- {
- while (!current.IsEmpty)
- {
- stack = stack.Push(current);
- current = current.Right;
- }
- current = stack.Peek();
- stack = stack.Pop();
- yield return current;
- }
- }
- // Static helpers for tree balancing
- private static int Height(IBinarySearchTree<TKey, TValue> tree)
- {
- if (tree.IsEmpty)
- return 0;
- return ((AVLTree<TKey, TValue>)tree).height;
- }
- private IBinarySearchTree<TKey, TValue> RotateLeft(IBinarySearchTree<TKey, TValue> tree)
- {
- if (tree.Right.IsEmpty)
- return tree;
- return new AVLTree<TKey, TValue>(tree.Comparer, deepCopyKey, deepCopyValue, tree.Right.Key, tree.Right.Value,
- new AVLTree<TKey, TValue>(tree.Comparer, deepCopyKey, deepCopyValue, tree.Key, tree.Value, tree.Left, tree.Right.Left),
- tree.Right.Right);
- }
- private IBinarySearchTree<TKey, TValue> RotateRight(IBinarySearchTree<TKey, TValue> tree)
- {
- if (tree.Left.IsEmpty)
- return tree;
- return new AVLTree<TKey, TValue>(tree.Comparer, deepCopyKey, deepCopyValue, tree.Left.Key, tree.Left.Value, tree.Left.Left,
- new AVLTree<TKey, TValue>(tree.Comparer, deepCopyKey, deepCopyValue, tree.Key, tree.Value, tree.Left.Right, tree.Right));
- }
- private IBinarySearchTree<TKey, TValue> DoubleLeft(IBinarySearchTree<TKey, TValue> tree)
- {
- if (tree.Right.IsEmpty)
- return tree;
- var rotatedRightChild = new AVLTree<TKey, TValue>(tree.Comparer, deepCopyKey, deepCopyValue, tree.Key, tree.Value, tree.Left, RotateRight(tree.Right));
- return RotateLeft(rotatedRightChild);
- }
- private IBinarySearchTree<TKey, TValue> DoubleRight(IBinarySearchTree<TKey, TValue> tree)
- {
- if (tree.Left.IsEmpty)
- return tree;
- var rotatedLeftChild = new AVLTree<TKey, TValue>(tree.Comparer, deepCopyKey, deepCopyValue, tree.Key, tree.Value, RotateLeft(tree.Left), tree.Right);
- return RotateRight(rotatedLeftChild);
- }
- private static int Balance(IBinarySearchTree<TKey, TValue> tree)
- {
- if (tree.IsEmpty)
- return 0;
- return Height(tree.Right) - Height(tree.Left);
- }
- private static bool IsRightHeavy(IBinarySearchTree<TKey, TValue> tree)
- {
- return Balance(tree) >= 2;
- }
- private static bool IsLeftHeavy(IBinarySearchTree<TKey, TValue> tree)
- {
- return Balance(tree) <= -2;
- }
- private IBinarySearchTree<TKey, TValue> MakeBalanced(IBinarySearchTree<TKey, TValue> tree)
- {
- IBinarySearchTree<TKey, TValue> result;
- if (IsRightHeavy(tree))
- {
- if (IsLeftHeavy(tree.Right))
- result = DoubleLeft(tree);
- else
- result = RotateLeft(tree);
- }
- else if (IsLeftHeavy(tree))
- {
- if (IsRightHeavy(tree.Left))
- result = DoubleRight(tree);
- else
- result = RotateRight(tree);
- }
- else
- result = tree;
- return result;
- }
- }
- }