/// <summary> /// Copies the contents of the SkipList to the passed-in array. /// </summary> public void CopyTo(T[] array, int index) { // copy the values from the skip list to array if (array == null) { throw new ArgumentNullException("array is null"); } if (index < 0) { throw new ArgumentOutOfRangeException("index is less than 0"); } if (index >= array.Length) { throw new ArithmeticException("index is greater than the length of array"); } if (array.Length - index <= this.Count) { throw new ArgumentException("insufficient space in array to store skip list starting at specified index"); } SkipListNode <T> current = this.head[0]; int i = 0; while (current != null) { array[i + index] = current.Value; i++; } }
// Clears out the contents of the SkipList and creates a new head, with height 1. public void Clear() { // create a new head this.head = null; this.head = new SkipListNode <T>(1); this.Count = 0; }
/// <summary> /// This overridden form of ToString() is simply for displaying detailed information /// about the contents of the SkipList, used by SkipListTester - feel free to remove it. /// </summary> public override string ToString() { SkipListNode <T> current = this.head[0]; System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder(); while (current != null) { stringBuilder.Append(current.Value.ToString()); stringBuilder.Append(" [ H=").Append(current.Height); for (int i = current.Height - 1; i >= 0; i--) { stringBuilder.Append(" | "); if (current[i] == null) { stringBuilder.Append("NULL"); } else { stringBuilder.Append(current[i].Value.ToString()); } } stringBuilder.Append(" ] ; "); current = current[0]; } return(stringBuilder.ToString()); }
/// <summary> /// Adds a new element to the SkipList. /// </summary> /// <param name="value">The value to add.</param> /// <remarks>This SkipList implementation does not allow for duplicates. Attempting to add a /// duplicate value will not raise an exception, it will simply exit the method without /// changing the SkipList.</remarks> public void Add(T value) { SkipListNode <T>[] updates = this.BuildUpdateTable(value); SkipListNode <T> current = updates[0]; // see if a duplicate is being inserted if (current[0] != null && this.comparer.Compare(current[0].Value, value) == 0) { // cannot enter a duplicate, handle this case by either just returning or by throwing an exception return; } // create a new node SkipListNode <T> n = new SkipListNode <T>(value, this.ChooseRandomHeight(head.Height + 1)); this.Count++; // if the node's level is greater than the head's level, increase the head's level if (n.Height > this.head.Height) { this.head.IncrementHeight(); this.head[this.head.Height - 1] = n; } // splice the new node into the list for (int i = 0; i < n.Height; i++) { if (i < updates.Length) { n[i] = updates[i][i]; updates[i][i] = n; } } }
public SkipListNode <T> FindByValue(T value) { SkipListNode <T> current = this.head; // first, determine the nodes that need to be updated at each level for (int i = this.head.Height - 1; i >= 0; i--) { while (current[i] != null) { this.ComparisonCount++; int results = this.comparer.Compare(current[i].Value, value); if (results == 0) { return(current[i]); // we found the item } else if (results < 0) { current = current[i]; // move on to the next neighbor } else { break; // exit while loop, we need to move down the height of the current node } } } // if we reach here, we searched to the end of the list without finding the element return(null); }
/// <summary> /// Returns an enumerator to access the contents of the SkipList. /// </summary> public IEnumerator <T> GetEnumerator() { // enumerate through the skip list one element at a time SkipListNode <T> current = this.head[0]; while (current != null) { yield return(current.Value); current = current[0]; } }
public SkipList(int randomSeed, IComparer <T> comparer) { this.head = new SkipListNode <T>(1); this.ComparisonCount = 0; this.Count = 0; this.Count++; if (randomSeed < 0) { randomNum = new Random(); } else { randomNum = new Random(randomSeed); } if (comparer != null) { this.comparer = comparer; } }
/// <summary> /// Attempts to remove a value from the SkipList. /// </summary> /// <param name="value">The value to remove from the SkipList.</param> /// <returns>True if the value is found and removed; false if the value is not found /// in the SkipList.</returns> public bool Remove(T value) { SkipListNode <T>[] updates = this.BuildUpdateTable(value); SkipListNode <T> current = updates[0][0]; if (current != null && this.comparer.Compare(current.Value, value) == 0) { this.Count--; // We found the data to delete for (int i = 0; i < this.head.Height; i++) { if (updates[i][i] != current) { break; } else { updates[i][i] = current[i]; } } // finally, see if we need to trim the height of the list if (this.head[this.head.Height - 1] == null) { // we removed the single, tallest item... reduce the list height this.head.DecrementHeight(); } current = null; return(true); // the item was successfully removed } else { // the data to delete wasn't found. return(false); } }
/// <summary> /// Creates a table of the SkipListNode instances that will need to be updated when an item is /// added or removed from the SkipList. /// </summary> /// <param name="value">The value to be added or removed.</param> /// <returns>An array of SkipListNode instances, as many as the height of the head node. /// A SkipListNode instance in array index k represents the SkipListNode at height k that must /// be updated following the addition/deletion.</returns> protected SkipListNode <T>[] BuildUpdateTable(T value) { SkipListNode <T>[] updates = new SkipListNode <T> [this.head.Height]; SkipListNode <T> current = this.head; // determine the nodes that need to be updated at each level for (int i = this.head.Height - 1; i >= 0; i--) { if (!(current[i] != null && this.comparer.Compare(current[i].Value, value) < 0)) { this.ComparisonCount++; } while (current[i] != null && this.comparer.Compare(current[i].Value, value) < 0) { current = current[i]; this.ComparisonCount++; } updates[i] = current; } return(updates); }