/*
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.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using NGenerics.Comparers;
using NGenerics.Patterns.Visitor;
namespace NGenerics.DataStructures.Trees
{
///
/// An implementation of a Red-Black tree.
///
/// The type of the keys in the .
/// The type of the values in the .
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
#if (!SILVERLIGHT && !WINDOWSPHONE)
//[Serializable]
#endif
public class RedBlackTree : RedBlackTree>, IDictionary // BinarySearchTreeBase
{
#region Construction
///
public RedBlackTree() : base(new KeyValuePairComparer())
{
// Do nothing - the default Comparer will be used by the base class.
}
///
public RedBlackTree(IComparer comparer)
: base(new KeyValuePairComparer(comparer))
{
// Do nothing else.
}
///
public RedBlackTree(Comparison comparison)
: base(new KeyValuePairComparer(comparison))
{
// Do nothing else.
}
#endregion
#region Private Members
private RedBlackTreeNode> FindNode(TKey key)
{
return base.FindNode(new KeyValuePair(key, default(TValue))) as RedBlackTreeNode>;
}
private bool Contains(KeyValuePair item, bool checkValue) {
var node = FindNode(item);
if ((node != null) && !checkValue) {
return true;
}
return node != null && Equals(item.Value, node.Data.Value);
}
#endregion
#region IDictionary Members
///
/// Removes the element with the specified key from the .
///
/// The key of the element to remove.
///
/// true if the element is successfully removed; otherwise, false. This method also returns false if was not found in the original .
///
///
/// is null.
///
///
/// The is read-only.
///
public bool Remove(TKey key) {
return Remove(new KeyValuePair(key, default(TValue)));
}
///
/// Adds an element with the provided key and value to the .
///
/// The object to use as the key of the element to add.
/// The object to use as the value of the element to add.
///
/// is null.
///
///
/// An element with the same key already exists in the .
///
///
/// The is read-only.
///
public void Add(TKey key, TValue value) {
if (Equals(key, null))
{
throw new ArgumentNullException("key");
}
Add(new KeyValuePair(key, value));
}
///
/// Determines whether the contains an element with the specified key.
///
/// The key to locate in the .
///
/// true if the contains an element with the key; otherwise, false.
///
///
/// is null.
///
public bool ContainsKey(TKey key) {
return Contains(new KeyValuePair(key, default(TValue)), false);
}
///
/// Gets an containing the keys of the .
///
///
///
///
///
///
public ICollection Keys
{
get
{
// Get the keys in sorted order
var visitor = new KeyTrackingVisitor();
var inOrderVisitor = new InOrderVisitor>(visitor);
DepthFirstTraversal(inOrderVisitor);
return new ReadOnlyCollection(visitor.TrackingList);
}
}
///
///
///
///
///
public bool TryGetValue(TKey key, out TValue value)
{
var node = FindNode(new KeyValuePair(key, default(TValue)));
if (node == null)
{
value = default(TValue);
return false;
}
value = node.Data.Value;
return true;
}
///
/// Gets an containing the values in the .
///
///
///
///
///
///
public ICollection Values
{
get
{
var visitor = new ValueTrackingVisitor();
var inOrderVisitor = new InOrderVisitor>(visitor);
DepthFirstTraversal(inOrderVisitor);
return new ReadOnlyCollection(visitor.TrackingList);
}
}
///
/// Gets or sets the value with the specified key.
///
/// The key of the item to set or get.
public TValue this[TKey key]
{
get
{
var node = FindNode(key);
if (node == null)
{
throw new KeyNotFoundException("key");
}
return node.Data.Value;
}
set
{
var node = FindNode(key);
if (node == null)
{
throw new KeyNotFoundException("key");
}
node.Data = new KeyValuePair(key, value);
}
}
#endregion
#region ICollection> Members
///
///
///
///
///
public override bool Contains(KeyValuePair item) {
return Contains(item, true);
}
#endregion
}
}