C5 is a comprehensive library of collection classes for the Common
Language Infrastructure (CLI). This guide describes prerelease
version 0.5 of C5.
C5 is a refactoring and extension of the generic collection classes developed by Peter Sestoft while visiting Microsoft Research in Cambridge.
Unless stated otherwise types mentioned below will belong to the "C5" namespace; and all code examples assume a "using C5;" clause (and no "using System.Collection.Generics;" clause)..
The goals in the development of the library has been
To create a library of collection classes for the CLI that can assist expert and non-expert programmers on the platform to develop correct and efficient applications.
The library should at least fill the gaps in the standard “System.Collections.Generics” namespace compared to standard collection class libraries for related object oriented languages like Java, and utilize the new facilities for generic programming. Microsoft recently (mid 2004) seems to have changed their minds and ntend to bridge that gap in the beta2 version of VS 2005 due at the end of 2004.
In order to fulfill the efficiency goal, the library utilizes first-class data structures inside its collection classes. The library has been constructed with the modern object oriented programming principle of "code to interfaces, not to implementations" in mind, while the interface architecture has been carefully crafted to reflect the efficient data structures actually existence.
A collection in the sense of this library is a plain "collection of items of a single type". A collection does not impose any other logical structure on its items than perhaps uniqueness or sequence ordering.
The main division line among the collection classes of this library is the distinction between "proper" collections and dictionaries. A dictionary is a class that defines a partial function (or map) from one item type (the keys) to another one (the values). A dictionary can be viewed as a collection of (key,value) pairs having the property of defining a partial function.
The item type for the collection classes are always given by generic parameters. For a proper collection, there will be a single parameter, customarily called T, as in HashSet<T>. For a dictionary there will be two - the key and value types - as in HashDictionary<K,V>.
A collection class, or rather the data structure inside, can be
either
equality based or comparison based. An equality based collection will
have an
associated so-called equalityComparer of type IEqualityComparer<T>,
where T is the item type of the collection. A comparison based
collection has an
associated comparer of type IComparer<T>.
The section below on creation of
collection classes
explains how the equalityComparers and comparers are chosen. NB: this design will
be modified soon, cf. Planned changes.
Collection classes in the library have either set or bag semantics.
A set
collection can at most contain one copy of an item, while bag
collections may
contain several. One can programmatically see at runtime if an editable
collection class has set or bag semantics by checking the
AllowsDuplicates
property. At compile time, refer to the set
or bag table
below for an overview.
The C5 library is designed to make it easy to program to interfaces instead of implementations. In particular, all public properties and methods of the collection classes belong to their implemented interfaces (except for the odd special diagnostic method and the odd mistake to be weeded out before release). The typical programming style would be
IList<int> lst = new LinkedList<int>();
lst.Add(7);
instead of
LinkedList<int> lst = new LinkedList<int>();
lst.Add(7);
Note that with this programming style, the Add call will be compiled to an interface call instead of a (virtual) method call, but interface calls on the CLR (at least the Microsoft implementation) are at most very slightly slower than virtual calls, so one should not shun the interface style for performance reasons.
We will discuss the collection classes available in C5 structured according to the main functional interfaces of the proper collections, the dictionaries and the interfaces of query results.
The following diagam shows the type hierarchy of the proper collection classes:
The most important interfaces - those that are directly
implemented by
collection classes - are listed to the left in this table with a short
description in the middle and all implementing classes to the
right.
Please see also the complete complexity table for more comprehensive guidance.
To identify which classes are equalityComparer or comparer based and which classes implement set or bag we use the following symbols:
set: S |
bag: B |
equalityComparer: H |
comparer: C |
Interface | Short description | Implementing classes |
---|---|---|
ICollection<T> | This is the fundamental type
of updateable collections. It has operations for searching for
items, for adding, updating and removing one or a bunch of items, for
clearing the collection and transforming the collection to an
array.
If one only needs these operations, the hash set and hash bag classes are fastest for if we have a equalityComparer for the items and the red-black tree classes are fastest if we must use a comparer. |
SH HashSet<T>BH HashBag<T>BH LinkedList<T>SH HashedLinkedList<T>BH ArrayList<T>SH HashedArrayList<T>SC SortedArray<T>SC TreeSet<T>BC TreeBag<T> |
IPriorityQueue<T> | This is a special case in the
library, being the only type of updateable collection interface that
does not implement IEditableCollection<T>. The reason for its
presence is the specialized "heap" data structures for priority queues
that only support these operations.
If one only needs these the priority queue operations and is satisfied with bag semantics, then IntervalHeap<P> is the fastest choice. |
BC IntervalHeap<T>SC TreeSet<T>BC TreeBag<T> |
IList<T> | This is an updateable collection
with sequence order imposed on the items by the user at insertion time
or by later rearrangements.
There are two main base data structures: dynamic arrays and doubly linked lists with very different complexity profile. The plain linked list is fast for operations at the end points only, while the plain array list have very fast lookups by index, but update operations are only fast at the right end point. The Hashed- variants employ an index based on a hash table. This speeds up lookups by item considerably and for the linked list variant also insertions before or after specific items. The index changes the classes from bags to sets. The hashed variants more than double the time of otherwise fast update operations, and should only be used when really needed. |
BH LinkedList<T>SH HashedLinkedList<T>BH ArrayList<T>SH HashedArrayList<T> |
IIndexedSorted<T> | This is an updateable collection
with sequence order given by a comparer.
There are two main data structures inside the implementations: red-black search trees and a dynamic array kept sorted at all times. The differences are chiefly that the trees have much faster update operations, while the sorted array is somewhat faster at index lookups. In fact, the sorted array should only be used for static operation, where the collection is created and populated and then not changed again. |
SC SortedArray<T>SC TreeSet<T>BC TreeBag<T> |
IPersistentSorted<T> | This is a sorted collection that support very fast clones that themselves are sorted. The only implementation is the tree implementation with set and bag variants. | SC TreeSet<T>BC TreeBag<T> |
There are two dictionary interfaces:
Interface | Short description | Implementing classes |
---|---|---|
IDictionary<K,V> | This is the base dictionary interface.
The choice is that one should use the hash dictionary unless one only has a comparer for the items, in which case the tree dictionary can be used. |
HashDictionary<K,V> TreeDictionary<K,V> |
ISortedDictionary<K,V> | This is a dictionary based on a comparer for the keys. There is only the tree implementation. | TreeDictionary<K,V> |
Some of the most basic collection interfaces have an important usage as the types of results of queries to collections, although these interfaces also appear at the base of the other collection interfaces and even as the types of synthetic collections. The interfaces in question are the standard System.Collections.Generics.IEnumerable<T>, ICollectionValue<T>, IDirectedEnumerable<T> and IDirectedCollectionValue<T>.
The differences between the "Enumerable" and "Collection" variants are that the "Enumerable" variant only knows how to enumerate through its items, the "Collection" variants also knows how many items it has (without having to walk through an enumeration). The "Directed" variants are used for results of queries to sequenced collections (implementing ISequenced<T>) and therefore have a non-implementation dependent enumeration order. The "Directed" variants supports two operations, Backwards() to enable enumeration in the opposite direction and Direction to tell if the enumeration order is forwards or backwards with respect to the original collection.
Note: operations on an enumerator created by the GetEnumerator() method on System.Collections.Generics.IEnumerable<T> cannot be interleaved with update operations on the underlying collection.
Note: for all enumerators in the library the operations have O(1) amortized complexity.
All collections classes in C5 have (zero parameter) default
constructors. So
if we want to make a linked list of items of some type, TheType
,
and add an item to the list we will do
IList<TheType> lst = new
LinkedList<TheType>();
TheType t = ...;
lst.Add(t);
The collection classes have no constructors that will take an array
or a
collection as parameter for prepopulating the collection, use the
AddAll method
instead. NB: in the released version, expect constructors with an
enumerable as argument and constructors with a variable number of
arguments ("params") for the initialization of the collection, see the planned changes section.
Some collection classes are governed by internal parameters that one
can give
non-default values at creation time (fill
in HashSet<T>,
HashBag<T>, HashDictionary<K,V>)
or use internal tables that one can expand in advance if one has
expectations of
how large the collection will grow (HashSet<T>,
HashBag<T>, HashDictionary<K,V>, ArrayList<T>,
HashedArrayList<T>,
SortedArray<T>,
IntervalHeap<T>).
For equality-based collection classes, these constructors will use a default equalityComparer to define equality of items according to the following table:
T | default equalityComparer (implements IEqualityComparer<T>) | Equality and hash code by |
---|---|---|
int | IntEqualityComparer | Equals and hash code of integer |
other value type | DefaultValueTypeEqualityComparer<T> | methods inherited from object |
IEditableCollection<S> | EqualityComparerBuilder.UnsequencedEqualityComparer<S,IEditableCollection<S>> | contents without regards to sequence |
ISequenced<S> | EqualityComparerBuilder.SequencedEqualityComparer<S,IEditableCollection<S>> | contents with regards to sequence |
other reference type | DefaultReferenceTypeEqualityComparer<T> | methods inherited from object |
For comparison-based collection classes, these constructors will use a default comparer:
T | default comparer (implements IComparer<T>) |
Comparison by |
---|---|---|
int | IC | Standard integer comparison |
implementing IComparable<T> | NaturalComparer<T> | The CompareTo(T o) instance method |
other implementing System.IComparable | NaturalComparerO<T> | The CompareTo(object o) instance method |
other | - | collection class constructor throws an exception |
Sometimes, the default equalityComparer or comparer is not the right one for
the
problem at hand. In that case one must get hold on a equalityComparer or comparer
of the
right kind and supply it to one of the constructors of the collection
classes
that supports such a parameter. The procedure is demonstrated in the
sections
below on external equalityComparers, external
comparers and collections
as items.
NB: in the released version, expect the equalityComparers and comparers to be of the System.Collections.Generics.IComparer<T> type, see the planned changes section.
In addition to the helper classes referenced above, the library has the helper class KeyValuePairEqualityComparer<K,V> to construct a equalityComparer for pairs of the type KeyValuePair<K,V>, the type of entry of a K to V dictionary. The constructed equalityComparer will only take the first component of the pair into account. We can use these classes in the following way to make a linked list (with hash index) of pairs of strings identified by their first components using some custom equalityComparer on strings:
IEqualityComparer<string> csh = ...;
IEqualityComparer<KeyValuePair<string,string>> cph =
new KeyValuePairEqualityComparer<string,string>(csh);
IList<KeyValuePair<string,string>> lst =
new HashedLinkedList<KeyValuePair<string,string>>(cph);
lst.Add(new KeyValuePair<string,string>("abe","kat"));
One may, of course, program a equalityComparer oneself. This one should always do if the item type is defined as a struct (value type) that does not override the Equals and GetHashCode methods of object, since in that case the default equalityComparer will use the slow default versions of those methods supplied by the runtime via reflection.
There is a helper class for comparer of pairs: KeyValuePairComparer<K,V>. We will show an example of a custom comparer. Imagine wanting to compare double precision floating point numbers with a tolerance. The following code snippet shows how one could make a tree set out of such numbers:
class DC : IComparer<double> {
const double eps = 1E-10;
int Compare(double a, double b)
{return a > b + eps ? 1 : a < b - eps ? -1 : 0;}
}
void dowork() {
IComparer<double> dc = new DC();
ISorted<double> tree = new TreeSet<double>(dc);
tree.Add(3.45);
...
}
In this particular case, one would have to make sure, that two different floating point numbers are only identified by the comparer if they really should represent the same value and not by coincidence.
When one wants to use a collection whose items itself are of collection type, one usually wants the interior collections to be identified by contents - either according to or irrespective of sequence order. An example could be transformations of Finite Automatons. The default equalityComparers and the EqualityComparerBuilder classes mentioned above may help to construct such collections of collections as in the examples that follow:
To make an array list of sequenced collections identified by contents in sequenced fashion one would simply do:
ArrayList<ISequenced<int>> lst = new ArrayList<ISequenced<int>>();
To make a linked list of linked lists identified by contents unsequenced, explicitly construct the collection equalityComparer:
IEqualityComparer<LinkedList<int>> lsth =
new EqualityComparerBuilder.UnsequencedEqualityComparer<int,LinkedList<int>>();
LinkedList<LinkedList<int>> lst =
new LinkedList<LinkedList<int>>(lsth);
If for some strange reason one would like to make a hash set of linked lists with the lists identified by reference equality one would simply do:
HashSet<LinkedList<int>> lst = new HashSet<LinkedList<int>>();
If for even stranger reasons one would make a hash set of ISequenced<int> collections with the collections identified by reference equality one would do like this:
IEqualityComparer<
ISequenced
<int>> lsth =
new DefaultReferenceTypeEqualityComparer<
ISequenced
<int>>();
HashSet<ISequenced
<int>> lst =
new HashSet<ISequenced
<int>>(lsth);
The following table shows which of the collection classes have set
semantics
and which have bag semantics. All the implemented classes have fixed,
compiled in semantics.
Note: when in a set collection, methods with an Add in the name will ignore attempts to add an item already there or flag the failed attempt by a Boolean return value; methods with an Insert in the name (only in lists) will throw an exception.
HashSet<T> | set |
HashBag<T> | bag |
LinkedList<T> | bag |
HashedLinkedList<T> | set |
ArrayList<T> | bag |
HashedArrayList<T> | set |
SortedArray<T> | set |
TreeSet<T> | set |
TreeBag<T> | bag |
IntervalHeap<T> | bag |
The IList<T> interface supports via the View method the functionality that one can zoom in on part of a list and use it as an IList<T> in its own right while having updates to the view passed through to the base (original) IList<T>. Using the Slide method calls, one may move the view around the base list. Using Slide repeatedly one can implement safe ways to iterate over a list while updating it. The IList<T> interface also has properties Underlying and Offset showing the base list of a view and the current site of a view.
One can create a view on a view, but the new view will have the original base list as base. A view will be invalidated if an update operation is performed on the base list by any other means than through this particular view.
The following code snippet shows a silly example of iterating over a list, doing an insertion each time certain combination of items are seen (the example iterates right to left and inserts 666 whenever two consecutive items have an odd difference):
IList<int> lst = ...;
IList<int> view = lst.CreateView(lst.Count-2, 2);
while (true) {
if ((view.Last - view.First) % 2 == 1)
view.Insert(1, 666);
if (view.Offset == 0)
break;
else
view.Slide(-1,2);
}
The search tree implementation in the library is based on node copy persistent red-black trees. The persistence is exposed in the Snapshot method that can be considered a very fast and space-saving way of making a read-only clone of the tree. When using persistence, the space use of a red-black tree in this implementation is linear in the number of operations since the creation of the tree.
One use of persistence could be to safely enumerate a tree interleaved with updates:
IPersistentSorted<int> tree = new TreeSet<int>();
tree.Add(5);
...
ISorted<int> snap = tree.Snapshot();
foreach (int i in snap)
tree.Add(i+7);
The GUITester project of the complete library source code contains an interesting (standard) usage of persistent search trees to the geometric problem of constructing an efficient data structure for point location in a division of the plane given by a list of line segments.
All interface methods and properties of the collection classes implemented in the library are virtual and so it should be safe to subclass these classes. Some classes may have protected members if they are subclassed in the library itself. We refer to the detailed reference manuals and the library source for information on the protected members and their role in subclassing.
There is a sequence of helper classes designed to be used as base classes of collection classes: EnumerableBase<T>, CollectionValueBase<T>, CollectionBase<T>, SequencedBase<T> and ArrayBase<T>. Please see the reference manual and the library source code for documentation and examples.
As for dictionaries, the DictionaryBase<K,V> class will construct a class implementing IDictionary<K,V> by simply plugging in a set implementation.
The library contains a long list of wrapper classes all with name starting with Guarded having the purpose of creating a read-only view of an existing collection. The wrapping is done by the constructors of the classes. If we want to give some code access to only lookup operations on a, say, list we can do as follows:
IList<int> lst;
...
IList<int> rolst = new GList<int>(lst);
OtherObject.dowork(rolst);
Please see the reference manual for details on available wrapper classes.
The following table shows the underlying data structure of the various collection classes.
Data structure | Classes | Primary Interfaces |
---|---|---|
hash table | HashSet<T> | ICollection<T> |
hash table | HashBag<T> | ICollection<T> |
hash table | HashDictionary<K,V> | IDictionary<K,V> |
linked list | LinkedList<T> | IList<T> |
linked list with hash index | HashedLinkedList<T> | IList<T> |
dynamic array | ArrayList<T> | IList<T> |
dynamic array with hash index | HashedArrayList<T> | IList<T> |
sorted dynamic array | SortedArray<T> | IIndexedSorted<T> |
heap | IntervalHeap<T> | IPriorityQueue<T> |
red-black search tree | TreeSet<T> | IIndexedSorted<T>, IPersistentSorted<T> |
red-black search tree | TreeBag<T> | IIndexedSorted<T>, IPersistentSorted<T> |
red-black search tree | TreeDictionary<K,V> | ISortedDictionary<K,V> |
This section overviews the complexities of cc public methods and property accesses.
In the table below, for lack of space we use the following numbers to identify collection classes:
Class | Column |
---|---|
HashSet<T> | HS |
HashBag<T> | HB |
ArrayList<T> | AL |
LinkedList<T> | LL |
HashedArrayList<T> | HAL |
HashedLinkedList<T> | HLL |
TreeSet<T> | RBTS |
TreeBag<T> | RBTB |
SortedArray<T> | SA |
IntervalHeap<T> | IH |
And the following special symbols:
n size of collection,
m size of argument if collection-: not supported
*: means: suboptimal complexity (library is in error)
$: special at end: the operation is much faster at the start and/or end
(end for
array list, both for linked list)
Note: we do not show return type or parameters for methods,
just mark
with ()
Note: we ignore time for reclaiming of internal array space (e.g. Clear)
User supplied operations like comparers or equalityComparers are assumed to be
O(1)
Member | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
---|---|---|---|---|---|---|---|---|---|---|
IEnumerable<T> | ||||||||||
GetEnumerator() | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) |
IDirectedEnumerable<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
Direction | - | - | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
Backwards() | - | - | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
ICollectionValue<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
Count | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) |
CopyTo | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) |
ToArray | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | - |
Apply() | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) |
Exists() | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) |
All() | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) | O(n) |
IDirectedCollectionValue<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
Backwards() | - | - | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
IExtensible<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
AllowsDuplicates | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) |
SyncRoot | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) |
IsEmpty | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) |
Add | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(log n) | O(log n) | O(n) | O(log n) |
AddAll | O(m) | O(m) | O(m) | O(m) | O(m) | O(m) | O(mlog n) | O(mlog n) | O(mlog n) | ?? |
ICollection<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
IsReadOnly | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
ContainsSpeed | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
GetHashCode | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
Equals | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
Contains | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
ContainsCount | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
ContainsAll | O(m) | O(m) | O(mn)* | O(mn)* | O(m) | O(m) | O(m logn) | O(m logn) | O(m logn) | - |
Find | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
FindOrAdd | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
Update | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
UpdateOrAdd | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
Remove | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
RemoveWithReturn | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
RemoveAllCopies | O(1) | O(1) | O(n) | O(n) | O(1) | O(1) | O(log n) | O(log n) | O(log n) | - |
RemoveAll | O(m) | O(m) | O(mn)* | O(mn)* | O(m+n) | O(m) | O(m logn) | O(m logn) | O(m logn) | - |
Clear | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
RetainAll | O(m)? | O(m) | O(mn)* | O(mn)* | O(m+n) | O(m) | O(m logn) | O(m logn) | O(m logn) | - |
ISequenced<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
GetHashCode | - | - | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
Equals | - | - | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | O(1) | - |
IIndexed<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
this[i] | - | - | O(1) | O(n)$ | O(1) | O(n)$ | O(log n) | O(log n) | O(log n) | - |
this[start,end] | - | - | O(1) | O(n) | O(1) | O(n) | O(log n) | O(log n) | O(log n) | - |
IndexOf() | - | - | O(n) | O(n) | O(1) | O(n) | O(log n) | O(log n) | O(log n) | - |
LastIndexOf() | - | - | O(n) | O(n) | O(1) | O(n) | O(log n) | O(log n) | O(log n) | - |
RemoveAt | - | - | O(n)$ | O(n)$ | O(n)$ | O(n)$ | O(log n) | O(log n) | O(n) | - |
RemoveInterval | - | - | O(n) | O(n) | O(n) | O(n) | O(n log n)* | O(n log n)* | O(n) | - |
IList<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
First | - | - | O(1) | O(1) | O(1) | O(1) | - | - | - | - |
Last | - | - | O(1) | O(1) | O(1) | O(1) | - | - | - | - |
FIFO | - | - | O(1) | O(1) | O(1) | O(1) | - | - | - | - |
this[i] | - | - | O(1) | O(n)$ | O(1) | O(n)$ | - | - | - | - |
Base | - | - | O(1) | O(1) | O(1) | O(1) | - | - | - | - |
Offset | - | - | O(1) | O(1) | O(1) | O(1) | - | - | - | - |
Map() | - | - | O(n) | O(n) | O(n) | O(n) | - | - | - | - |
Insert() | - | - | O(n)$ | O(n)$ | O(n)$ | O(n)$ | - | - | - | - |
InsertFirst() | - | - | O(n) | O(1) | O(n) | O(1) | - | - | - | - |
InsertLast() | - | - | O(1) | O(1) | O(1) | O(1) | - | - | - | - |
InsertBefore() | - | - | O(n) | O(n) | O(n) | O(1) | - | - | - | - |
InsertAfter() | - | - | O(n) | O(n) | O(n) | O(1) | - | - | - | - |
InsertAll() | - | - | O(m+n) | O(m+n) | O(m+n) | O(m+n) | - | - | - | - |
FindAll() | - | - | O(n) | O(n) | O(n) | O(n) | - | - | - | - |
Remove() | - | - | O(n)$ | (1) | O(n)$ | O(1) | - | - | - | - |
RemoveFirst() | - | - | O(n) | O(1) | O(n) | O(1) | - | - | - | - |
RemoveLast() | - | - | O(1) | O(1) | O(1) | O(1) | - | - | - | - |
View() | - | - | O(1) | O(n) | O(1) | O(n) | - | - | - | - |
Slide() (amount: d) | - | - | O(d) | O(d) | O(d) | O(d) | - | - | - | - |
Reverse() | - | - | O(n) | O(n) | O(n) | O(n) | - | - | - | - |
IsSorted() | - | - | O(n) | O(n) | O(n) | O(n) | - | - | - | - |
Sort() | - | - | O(n log n) | O(n log n) | O(n log n) | O(n log n) | - | - | - | - |
Shuffle() | - | - | O(n) | O(n) | O(n) | O(n) | - | - | - | - |
IPriorityQueue<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
FindMin() | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | O(1) |
DeleteMin() | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | O(log n) |
FindMax() | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | O(1) |
DeleteMax() | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | O(log n) |
Comparer | - | - | - | - | - | - | O(1) | O(1) | O(1) | O(1) |
ISorted<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
Predecessor | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
Successor | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
WeakPredecessor | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
WeakSuccessor | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
Cut | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
RangeFrom | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
RangeFromTo | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
RangeTo | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
RangeAll | - | - | - | - | - | - | O(1) | O(1) | O(1) | - |
AddSorted | - | - | - | - | - | - | ? | ? | ? | - |
RemoveRangeFrom | - | - | - | - | - | - | O(nlog n)* | O(nlog n)* | O(n) | - |
RemoveRangeFromTo | - | - | - | - | - | - | O(nlog n)* | O(nlog n)* | O(n) | - |
RemoveRangeTo | - | - | - | - | - | - | O(nlog n)* | O(nlog n)* | O(n) | - |
IIndexedSorted<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
Map | - | - | - | - | - | - | O(n) | O(n) | O(n) | - |
CountFrom | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
CountFromTo | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
CountTo | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
RangeFrom | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
RangeFromTo | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
RangeTo | - | - | - | - | - | - | O(log n) | O(log n) | O(log n) | - |
FindAll | - | - | - | - | - | - | O(n) | O(n) | O(n) | - |
IPersistentSorted<T> | HS | HB | AL | LL | HAL | HLL | RBTS | RBTB | SA | IH |
Snapshot() | - | - | - | - | - | - | O(1) | O(1) | - | - |
Member | HashDictionary<K,V> | TreeDictionary<K,V> |
---|---|---|
IEnumerable<KeyValuePair<K,V>> | ||
GetEnumerator() | O(1) | O(1) |
IDictionary<K,V> | ||
this[key] | O(1) | O(log n) |
Count | O(1) | O(1) |
IsReadOnly | O(1) | O(1) |
SyncRoot | O(1) | O(1) |
Keys | O(1) | O(1) |
Values | O(1) | O(1) |
Add() | O(1) | O(log n) |
Remove() | O(1) | O(log n) |
Clear() | O(1) | O(1) |
Contains() | O(1) | O(log n) |
Find() | O(1) | O(log n) |
Update() | O(1) | O(log n) |
FindOrAdd | O(1) | O(log n) |
UpdateOrAdd | O(1) | O(log n) |
ISortedDictionary<K,V> | ||
Predecessor | - | O(log n) |
Successor | - | O(log n) |
WeakPredecessor | - | O(log n) |
WeakSuccessor | - | O(log n) |