using System; using System.Collections.Generic; using System.Diagnostics.Contracts; namespace DataStructures.SkipListSpace { /// /// Key value pair implemented in Skip List /// /// Key in key value pair /// Value in key value pair [Serializable] public partial class SkipList : IEnumerable, ICollection where TKey : IComparable { private readonly object lockObject = new object(); private readonly int maxLevel; private int level; private SkipNode header; private readonly NullSkipNode NullNode; private double probability; private const double Probability = 0.5; private readonly Random random = new Random(); public int Count { get; private set; } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return lockObject; } } [ContractInvariantMethod] private void ObjectInvariant() { Contract.Invariant(probability > 0); Contract.Invariant(probability < 1); Contract.Invariant(maxLevel > 0); } private SkipList(double probable, int maxLevel) { Contract.Requires(maxLevel > 0); Contract.Requires(probable < 1); Contract.Requires(probable > 0); this.probability = probable; this.maxLevel = maxLevel; level = 0; header = new SkipNode(maxLevel); NullNode = new NullSkipNode(maxLevel); //Initially all the forward links node of dummy header is NullNode for (int i = 0; i < maxLevel; i++) { header.Links[i] = NullNode; } } public static SkipList CreateInstance(long maxNodes) { return new SkipList(Probability, (int)(Math.Ceiling(Math.Log(maxNodes) / Math.Log(1 / Probability) - 1))); } private int GetRandomLevel() { Contract.Ensures(Contract.Result() >= 0); Contract.Ensures(Contract.Result() < maxLevel); int newLevel = 0; double ran = random.NextDouble(); while ((newLevel < maxLevel) && (ran < probability)) { newLevel++; } return newLevel; } /// /// Insert key value pair in list /// /// /// public void Insert(TKey key, TValue value) { Contract.Requires(key != null, "key"); SkipNode[] update = new SkipNode[maxLevel]; //Start search for each level from dummy header node SkipNode cursor = header; //Start from current max initialized header for (int i = level; i >= 0; i--) { //Find the node which is previous node to current code in any level while (cursor.Links[i].Key.CompareTo(key) == -1) { cursor = cursor.Links[i]; } //Put the predecessor node link in the level of update list update[i] = cursor; } //Check level 0 next whether we already have that element cursor = cursor.Links[0]; if (cursor.Key.CompareTo(key) == 0) { //Assign new value to corresponding key cursor.Value = value; } else { //If this is new node, then //Find random level for insertion int newLevel = GetRandomLevel(); //New node level is greater then current level //Update intermediate nodes if (newLevel > level) { //This is a special case, where dummy header links aren't initialized yet for (int i = level + 1; i < newLevel; i++) { //These levels of header aren't initialized yet update[i] = header; } //update current level, until this level from bottom header link is initialized level = newLevel; } //New node which will be inserted into new level, also needs newLevel number of forward edges cursor = new SkipNode(newLevel, key, value); //Insert the node for (int i = 0; i < newLevel; i++) { //Update edges of all the levels below to that level //New node is set to successor node its predecessor cursor.Links[i] = update[i].Links[i]; //Update forward edges of predecessor to currently inserted node update[i].Links[i] = cursor; } Count++; } } /// /// Delete from skip list if element exists /// /// Key to be deleted public void Delete(TKey key) { Contract.Requires(key != null); SkipNode[] update = new SkipNode[maxLevel + 1]; SkipNode cursor = header; for (int i = level; i >= 0; i--) { while (cursor.Links[i].Key.CompareTo(key) == -1) { cursor = cursor.Links[i]; } update[i] = cursor; } cursor = cursor.Links[0]; //Check is this the element we want to delete? if (cursor.Key.CompareTo(key) == 0) { for (int i = 0; i < level; i++) { //If next element is our to be deleted element //Check prev node point to next node if (update[i].Links[i] == cursor) { update[i].Links[i] = cursor.Links[i]; } } //Readjust levels of initialized links of dummy header while ((level > 0) && (header.Links[level].Key.Equals(NullNode))) { level--; } Count--; } //Element isn't in the list, just return } /// /// Search for values, given a key /// /// Key to be searched /// Value otherwise type default public TValue Search(TKey key) { Contract.Requires(key != null); SkipNode cursor = header; for (int i = 0; i < level; i++) { SkipNode nextElement = cursor.Links[i]; while (nextElement.Key.CompareTo(key) == -1) { cursor = nextElement; nextElement = cursor.Links[i]; } } //Got previous element of current key in the list //So next element must our searched element if list contains that element cursor = cursor.Links[0]; if (cursor.Key.Equals(key)) { return cursor.Value; } else { //Element is not in the list, return default return default(TValue); } } public void CopyTo(Array array, int index) { Contract.Requires(array != null, "array"); Contract.Requires(index >= 0, "index"); Contract.Requires(array.Length < Count); int i = index; var node = header.Links[0]; while (node != null) { array.SetValue(node.Value, i); node = node.Links[0]; i++; } } public IEnumerator GetEnumerator() { var node = header.Links[0]; while (node != null) { yield return node.Value; node = node.Links[0]; } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } }