📄 orderedset.cs
字号:
//******************************
// Written by Peter Golde
// Copyright (c) 2004-2005, Wintellect
//
// Use and restribution of this code is subject to the license agreement
// contained in the file "License.txt" accompanying this file.
//******************************
using System;
using System.Collections.Generic;
using System.Collections;
namespace Wintellect.PowerCollections
{
/// <summary>
/// OrderedSet<T> is a collection that contains items of type T.
/// The item are maintained in a sorted order, and duplicate items are not allowed. Each item has
/// an index in the set: the smallest item has index 0, the next smallest item has index 1,
/// and so forth.
/// </summary>
/// <remarks>
/// <p>The items are compared in one of three ways. If T implements IComparable<TKey> or IComparable,
/// then the CompareTo method of that interface will be used to compare items. Alternatively, a comparison
/// function can be passed in either as a delegate, or as an instance of IComparer<TKey>.</p>
/// <p>OrderedSet is implemented as a balanced binary tree. Inserting, deleting, and looking up an
/// an element all are done in log(N) type, where N is the number of keys in the tree.</p>
/// <p><see cref="Set<T>"/> is similar, but uses hashing instead of comparison, and does not maintain
/// the items in sorted order.</p>
///</remarks>
///<seealso cref="Set<T>"/>
[Serializable]
public class OrderedSet<T> : CollectionBase<T>, ICollection<T>, ICloneable
{
// The comparer used to compare items.
private IComparer<T> comparer;
// The red-black tree that actually does the work of storing the items.
private RedBlackTree<T> tree;
#region Constructors
/// <summary>
/// Creates a new OrderedSet. The T must implement IComparable<T>
/// or IComparable.
/// The CompareTo method of this interface will be used to compare items in this set.
/// </summary>
///<remarks>
/// Items that are null are permitted, and will be sorted before all other items.
///</remarks>
/// <exception cref="InvalidOperationException">T does not implement IComparable<TKey>.</exception>
public OrderedSet():
this(Comparers.DefaultComparer<T>())
{
}
/// <summary>
/// Creates a new OrderedSet. The passed delegate will be used to compare items in this set.
/// </summary>
/// <param name="comparison">A delegate to a method that will be used to compare items.</param>
public OrderedSet(Comparison<T> comparison) :
this(Comparers.ComparerFromComparison<T>(comparison))
{
}
/// <summary>
/// Creates a new OrderedSet. The Compare method of the passed comparison object
/// will be used to compare items in this set.
/// </summary>
/// <remarks>
/// The GetHashCode and Equals methods of the provided IComparer<T> will never
/// be called, and need not be implemented.
/// </remarks>
/// <param name="comparer">An instance of IComparer<T> that will be used to compare items.</param>
public OrderedSet(IComparer<T> comparer)
{
if (comparer == null)
throw new ArgumentNullException("comparer");
this.comparer = comparer;
tree = new RedBlackTree<T>(comparer);
}
/// <summary>
/// Creates a new OrderedSet. The T must implement IComparable<T>
/// or IComparable.
/// The CompareTo method of this interface will be used to compare items in this set. The set is
/// initialized with all the items in the given collection.
/// </summary>
///<remarks>
/// Items that are null are permitted, and will be sorted before all other items.
///</remarks>
/// <param name="collection">A collection with items to be placed into the OrderedSet.</param>
/// <exception cref="InvalidOperationException">T does not implement IComparable<TKey>.</exception>
public OrderedSet(IEnumerable<T> collection):
this(collection, Comparers.DefaultComparer<T>())
{
}
/// <summary>
/// Creates a new OrderedSet. The passed delegate will be used to compare items in this set.
/// The set is initialized with all the items in the given collection.
/// </summary>
/// <param name="collection">A collection with items to be placed into the OrderedSet.</param>
/// <param name="comparison">A delegate to a method that will be used to compare items.</param>
public OrderedSet(IEnumerable<T> collection, Comparison<T> comparison):
this(collection, Comparers.ComparerFromComparison<T>(comparison))
{
}
/// <summary>
/// Creates a new OrderedSet. The Compare method of the passed comparison object
/// will be used to compare items in this set. The set is
/// initialized with all the items in the given collection.
/// </summary>
/// <remarks>
/// The GetHashCode and Equals methods of the provided IComparer<T> will never
/// be called, and need not be implemented.
/// </remarks>
/// <param name="collection">A collection with items to be placed into the OrderedSet.</param>
/// <param name="comparer">An instance of IComparer<T> that will be used to compare items.</param>
public OrderedSet(IEnumerable<T> collection, IComparer<T> comparer):
this(comparer)
{
AddMany(collection);
}
/// <summary>
/// Creates a new OrderedSet given a comparer and a tree that contains the data. Used
/// internally for Clone.
/// </summary>
/// <param name="comparer">Comparer for the set.</param>
/// <param name="tree">Data for the set.</param>
private OrderedSet(IComparer<T> comparer, RedBlackTree<T> tree)
{
this.comparer = comparer;
this.tree = tree;
}
#endregion Constructors
#region Cloning
/// <summary>
/// Makes a shallow clone of this set; i.e., if items of the
/// set are reference types, then they are not cloned. If T is a value type,
/// then each element is copied as if by simple assignment.
/// </summary>
/// <remarks>Cloning the set takes time O(N), where N is the number of items in the set.</remarks>
/// <returns>The cloned set.</returns>
object ICloneable.Clone()
{
return this.Clone();
}
/// <summary>
/// Makes a shallow clone of this set; i.e., if items of the
/// set are reference types, then they are not cloned. If T is a value type,
/// then each element is copied as if by simple assignment.
/// </summary>
/// <remarks>Cloning the set takes time O(N), where N is the number of items in the set.</remarks>
/// <returns>The cloned set.</returns>
public OrderedSet<T> Clone()
{
OrderedSet<T> newSet = new OrderedSet<T>(comparer, tree.Clone());
return newSet;
}
/// <summary>
/// Makes a deep clone of this set. A new set is created with a clone of
/// each element of this set, by calling ICloneable.Clone on each element. If T is
/// a value type, then each element is copied as if by simple assignment.
/// </summary>
/// <remarks><para>If T is a reference type, it must implement
/// ICloneable. Otherwise, an InvalidOperationException is thrown.</para>
/// <para>Cloning the set takes time O(N log N), where N is the number of items in the set.</para></remarks>
/// <returns>The cloned set.</returns>
/// <exception cref="InvalidOperationException">T is a reference type that does not implement ICloneable.</exception>
public OrderedSet<T> CloneContents()
{
bool itemIsValueType;
if (!Util.IsCloneableType(typeof(T), out itemIsValueType))
throw new InvalidOperationException(string.Format(Strings.TypeNotCloneable, typeof(T).FullName));
OrderedSet<T> clone = new OrderedSet<T>(comparer);
// Clone each item, and add it to the new ordered set.
foreach (T item in this) {
T itemClone;
if (itemIsValueType)
itemClone = item;
else {
if (item == null)
itemClone = default(T); // Really null, because we know T is a reference type
else
itemClone = (T)(((ICloneable)item).Clone());
}
clone.Add(itemClone);
}
return clone;
}
#endregion Cloning
#region Basic collection containment
/// <summary>
/// Returns the IComparer<T> used to compare items in this set.
/// </summary>
/// <value>If the set was created using a comparer, that comparer is returned. If the set was
/// created using a comparison delegate, then a comparer equivalent to that delegate
/// is returned. Otherwise
/// the default comparer for T (Comparer<T>.Default) is returned.</value>
public IComparer<T> Comparer
{
get
{
return this.comparer;
}
}
/// <summary>
/// Returns the number of items in the set.
/// </summary>
/// <remarks>The size of the set is returned in constant time.</remarks>
/// <value>The number of items in the set.</value>
public sealed override int Count
{
get {
return tree.ElementCount;
}
}
/// <summary>
/// Returns an enumerator that enumerates all the items in the set.
/// The items are enumerated in sorted order.
/// </summary>
/// <remarks>
/// <p>Typically, this method is not called directly. Instead the "foreach" statement is used
/// to enumerate the items, which uses this method implicitly.</p>
/// <p>If an item is added to or deleted from the set while it is being enumerated, then
/// the enumeration will end with an InvalidOperationException.</p>
/// <p>Enumeration all the items in the set takes time O(N log N), where N is the number
/// of items in the set.</p>
/// </remarks>
/// <returns>An enumerator for enumerating all the items in the OrderedSet.</returns>
public sealed override IEnumerator<T> GetEnumerator()
{
return tree.GetEnumerator();
}
/// <summary>
/// Determines if this set contains an item equal to <paramref name="item"/>. The set
/// is not changed.
/// </summary>
/// <remarks>Searching the set for an item takes time O(log N), where N is the number of items in the set.</remarks>
/// <param name="item">The item to search for.</param>
/// <returns>True if the set contains <paramref name="item"/>. False if the set does not contain <paramref name="item"/>.</returns>
public sealed override bool Contains(T item)
{
T dummy;
return tree.Find(item, false, false, out dummy);
}
/// <summary>
/// <para>Determines if this set contains an item equal to <paramref name="item"/>, according to the
/// comparison mechanism that was used when the set was created. The set
/// is not changed.</para>
/// <para>If the set does contain an item equal to <paramref name="item"/>, then the item from the set is returned.</para>
/// </summary>
/// <remarks>Searching the set for an item takes time O(log N), where N is the number of items in the set.</remarks>
/// <example>
/// In the following example, the set contains strings which are compared in a case-insensitive manner.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -