C5 User's guide for prerelease version 0.5

Table of contents

Overview

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

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.

Interfaces

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.

"Proper" collection interfaces

The following diagam shows the type hierarchy of the proper collection classes:

Interface hierarchy
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>

Dictionary interfaces

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>

Query result interfaces

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.

To construct a collection

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.

To use an external equalityComparer

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. 

To use an external comparer

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.

To make collections of collections

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);

Special topics

To choose a set or bag collection

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

To work on part of a list: list views

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);
}

To work with persistent red-black trees

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.

To implement new collection classes or subclass an existing one

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.

To present a read only view of a collection

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.

Collection classes by data structure/class

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>

<>Planned architecture or interface changes for first release

  1. Eliminate the use of our own generic equality/comparator types, C5.IComparer<T> and C5.IEqualityComparer<T> and use the new design of VS 2005 beta1 in the form of the combined System.Collections.Generic.IComparer<T>.
  2. Vararg (params) constructors? (And IEnum do.)
  3. Possibly extended use of "wildcard style" operations like AddAll<U>(IEnumerable<U> items)?
  4. Make all collection classes clonable and serializable.

Performance details for proper collection classes

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) - -

Performance details for dictionary classes

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)