private SkipListNode <TKey, TValue>[] FindRightMostNodes(TKey key) { var rightNodes = new SkipListNode <TKey, TValue> [maximumLevelToUse]; // Start at the top list header node var currentNode = headNodes[CurrentListLevel]; for (var i = CurrentListLevel; i >= 0; i--) { while ((currentNode.Right != tail) && (comparerToUse.Compare(currentNode.Right.Key, key) < 0)) { currentNode = currentNode.Right; } // Store this node - the new node will be to the right of it. rightNodes[i] = currentNode; // Check if there is a next level, and if there is move down. if (i > 0) { currentNode = currentNode.Down; } } return(rightNodes); }
/// <summary> /// Adds the item to the collection. /// </summary> /// <param name="key">The key of the item.</param> /// <param name="value">The value to add to the colleciton.</param> /// <remarks> /// <b>Notes to Inheritors: </b> /// Derived classes can override this method to change the behavior of the <see cref="Add(TKey,TValue)"/> method. /// </remarks> protected virtual void AddItem(TKey key, TValue value) { var rightNodes = FindRightMostNodes(key); // Check if the item already exists in the list. If it does, throw an exception - // we will not allow duplicate items here. if ((rightNodes[0].Right != tail) && (comparerToUse.Compare(rightNodes[0].Right.Key, key) == 0)) { throw new ArgumentException("The item is already in the list.", "key"); } var newLevel = PickRandomLevel(); if (newLevel > CurrentListLevel) { for (var i = CurrentListLevel + 1; i <= newLevel; i++) { rightNodes[i] = headNodes[i]; } CurrentListLevel = newLevel; } var newNode = new SkipListNode <TKey, TValue>(key, value) { Right = rightNodes[0].Right }; // Insert the item in the first level rightNodes[0].Right = newNode; // And now insert the node in the rest of the levels, making sure // to update the the links for (var i = 1; i <= CurrentListLevel; i++) { var previousNode = newNode; newNode = new SkipListNode <TKey, TValue>(key, value) { Right = rightNodes[i].Right }; rightNodes[i].Right = newNode; newNode.Down = previousNode; } Count++; }
/// <param name="maximumLevel">The maximum level.</param> /// <param name="probability">The probability.</param> /// <param name="comparer">The comparer.</param> /// <exception cref="ArgumentNullException"><paramref name="comparer"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="maximumLevel"/> is less than 1.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="probability"/> is less than 0.1.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="probability"/> is greater than 0.9.</exception> public SkipList(int maximumLevel, double probability, IComparer <TKey> comparer) { #region Validation if (maximumLevel < 1) { throw new ArgumentOutOfRangeException("maximumLevel", "The maximum level must be bigger than 0."); } Guard.ArgumentNotNull(comparer, "comparer"); if ((probability > 0.9) || (probability < 0.1)) { throw new ArgumentOutOfRangeException("probability", "The probability must be between 0.1 and 0.9"); } #endregion comparerToUse = comparer; maximumLevelToUse = maximumLevel; probabilityToUse = probability; // Initialise the skip list to empty nodes, and link the heads and the tails headNodes = new SkipListNode <TKey, TValue> [maximumLevel]; headNodes[0] = new SkipListNode <TKey, TValue> { Right = tail }; for (var i = 1; i < maximumLevel; i++) { headNodes[i] = new SkipListNode <TKey, TValue> { Down = headNodes[i - 1], Right = tail }; //headNodes[i - 1].Up = headNodes[i]; } }