namespace System.Collections.Generic { /// /// Skip list implementation. /// /// Provided type. [Serializable] public sealed class SkipList : ICollection where T : IComparable { #region Fields [Serializable] private class NodeSet { public TKey Key; public int Level; public NodeSet[] Next; public NodeSet(TKey key, int level) { this.Key = key; this.Level = level; Next = new NodeSet[level + 1]; } } private int count; private readonly Random random; private readonly NodeSet head; private readonly NodeSet end; private readonly int maxLevel = 10; private int level; #endregion #region Properties /// /// Number of elements in the list. /// public int Count { get => count; } /// /// Specifies if the collection can be modified. /// public bool IsReadOnly { get; set; } #endregion #region Constructors /// /// Creates a new instance of SkipList collection. /// /// Maximum level of the skip list. public SkipList(int maxLevel = 10) { this.maxLevel = maxLevel; random = new Random(); head = new NodeSet(default, maxLevel); end = head; for (var i = 0; i <= maxLevel; i++) { head.Next[i] = end; } } #endregion #region Public Methods /// /// Adds an item to the collection. /// /// Item to be added. public void Add(T item) { var curNode = head; var newLevel = 0; while (random.Next(0, 2) > 0 && newLevel < maxLevel) { newLevel++; } if (newLevel > level) { level = newLevel; } var newNode = new NodeSet(item, newLevel); for (var i = 0; i <= newLevel; i++) { if (i > curNode.Level) { curNode = head; } while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0) { curNode = curNode.Next[i]; } newNode.Next[i] = curNode.Next[i]; curNode.Next[i] = newNode; } count++; } /// /// Removes provided item from the collection. /// /// Item to be removed. /// True if removal was successful. public bool Remove(T item) { var removed = false; var curNode = head; for (var i = 0; i <= maxLevel; i++) { if (i > curNode.Level) { curNode = head; } while (curNode.Next[i] != end && curNode.Next[i].Key.CompareTo(item) < 0) { curNode = curNode.Next[i]; } if (curNode.Next[i].Key.CompareTo(item) == 0) //Item is present on this level { curNode.Next[i] = curNode.Next[i].Next[i]; removed = true; } else { break; } } if (removed) { count--; return true; } else { return false; } } /// /// Clears the collection. /// public void Clear() { for (var i = 0; i < maxLevel; i++) { head.Next[i] = end; } count = 0; } /// /// Checks if item is present in the collection. /// /// Item to be checked. /// True if item is present in the collection. public bool Contains(T item) { if (Find(item) != null) { return true; } return false; } /// /// Copies the skip list contents onto the provided array. /// /// Array to hold the values from the list. /// Index to start insertion in the array. public void CopyTo(T[] array, int arrayIndex) { var node = head.Next[0]; while (node != end) { array[arrayIndex] = node.Key; arrayIndex++; node = node.Next[0]; } } /// /// Copies the elements from the collection into an array. /// /// Array filled with elements from the collection. public T[] ToArray() { var array = new T[count]; var index = 0; var curNode = head.Next[0]; while (curNode != end) { array[index] = curNode.Key; index++; curNode = curNode.Next[0]; } return array; } /// /// Enumerator that iterates over the collection. /// /// public IEnumerator GetEnumerator() { var curNode = head.Next[0]; while (curNode != end) { yield return curNode.Key; curNode = curNode.Next[0]; } } #endregion #region Private Methods IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } private NodeSet Find(T key) { var curNode = head; for (var i = level; i >= 0; i--) { while (curNode.Next[i] != end) { if (curNode.Next[i].Key.CompareTo(key) > 0) { break; } else if (curNode.Next[i].Key.CompareTo(key) == 0) { return curNode.Next[i]; } curNode = curNode.Next[i]; } } curNode = curNode.Next[0]; if (curNode != end && curNode.Key.CompareTo(key) == 0) { return curNode; } return null; } #endregion } }