/// <summary> /// Increases the height of the <see cref="SkipListNode{T}"/> by 1. Used for the head node of the <see cref="SkipList{T}"/>. /// </summary> internal void IncrementHeight() { var newForwards = new SkipListNode <T> [Height + 1]; for (int i = 0; i < Height; i++) { newForwards[i] = forwards[i]; } forwards = newForwards; }
/// <summary> /// Decreases the height of the <see cref="SkipListNode{T}"/> by 1. Used for the head node of the <see cref="SkipList{T}"/>. /// </summary> internal void DecrementHeight() { if (Height == 1) { return; } var newForwards = new SkipListNode <T> [Height - 1]; for (int i = 0; i < Height - 1; i++) { newForwards[i] = forwards[i]; } forwards = newForwards; }
/// <summary> /// Removes all elements from the <see cref="SkipList{T}"/>. /// </summary> public void Clear() { var curNode = Head; var lastNode = Head; while (curNode != null) { curNode = curNode[0]; lastNode.Invalidate(); lastNode = curNode; } Head = new SkipListNode <T>(default(T), 1); Count = 0; randomizer = new Random(); }
/// <summary> /// Adds a value in the <see cref="SkipList{T}"/>. /// </summary> /// <param name="value">The value to add in the <see cref="SkipList{T}"/>.</param> public void Add(T value) { // Gets the nodes which have to be updated(the nodes before the one we want to insert) var nodesForUpdate = new SkipListNode <T> [Height]; var curNode = Head; for (int i = Height - 1; i >= 0; i--) { while (curNode[i] != null && value.CompareTo(curNode[i].Value) > 0) { curNode = curNode[i]; } nodesForUpdate[i] = curNode; } // Check if inserting a duplicate var nodeBeforeNodeForInsertion = nodesForUpdate[0]; if (nodeBeforeNodeForInsertion[0] != null && value.CompareTo(nodeBeforeNodeForInsertion[0].Value) == 0) { throw new ArgumentException("Tried to insert duplicate value!"); } // Generates the height of the new node int height = 1; while (randomizer.NextDouble() < probability && height < Head.Height + 1) { height++; } // Creating the new node var newNode = new SkipListNode <T>(value, height); if (height > Head.Height)// If the new node is higher that the head node { // Icrease the head level Head.IncrementHeight(); Head[Head.Height - 1] = newNode; } // Adding the new node in the list for (int i = 0; i < newNode.Height; i++) { // For every level which have to be updated if (i < nodesForUpdate.Length) { // The new node starts to point where the node before it points. newNode[i] = nodesForUpdate[i][i]; // The old node starts to point to the new inserted node. nodesForUpdate[i][i] = newNode; // Note: // nodesForUpdate is an array of the nodes before the one we add. // nodesForUpdate[i] is the node on the level i before our new node. // nodesForUpdate[i][i] is the reference to the next node on level i. } } Count++; }
/// <summary> /// Creates a new instance of the <see cref="DoublyLinkedList{T}"/> class that is empty. /// </summary> public SkipList() { Head = new SkipListNode <T>(default(T), 1); Count = 0; randomizer = new Random(); }
/// <summary> /// Removes a value from the <see cref="SkipList{T}"/>. /// </summary> /// <param name="item">The value to remove from the <see cref="SkipList{T}"/>.</param> /// <returns>true if the value is removed successfully; otherwise false.</returns> public bool Remove(T value) { if (Count == 0) { return(false); } // Gets the nodes which have to be updated(the nodes before the one we will delete) var nodesForUpdate = new SkipListNode <T> [Height]; var curNode = Head; for (int i = Height - 1; i >= 0; i--) { while (curNode[i] != null && value.CompareTo(curNode[i].Value) > 0) { curNode = curNode[i]; } nodesForUpdate[i] = curNode; } var nodeToDelete = nodesForUpdate[0][0]; if (nodeToDelete != null && value.CompareTo(nodeToDelete.Value) == 0) { // Removing references to the node for deletion and changing them to the node after it for (int i = 0; i < Head.Height; i++) { if (nodesForUpdate[i][i] != nodeToDelete) { break; } else { nodesForUpdate[i][i] = nodeToDelete[i]; } // the node now points to the node after the node for removal // Note: // nodesForUpdate is an array of the nodes before the one we are deleting. // nodesForUpdate[i] is the node on the level i before the node for removal. // nodesForUpdate[i][i] is the reference to the next node on level i. } // Removing references of deleted node nodeToDelete.Invalidate(); // Check if we have to decrease the list level if (Head[Head.Height - 1] == null) { Head.DecrementHeight(); } Count--; return(true); } else { return(false); } }