using System; using System.Collections.Generic; namespace HeuristicLab.Problems.ProgramSynthesis.Push.Data.List { using System.Collections; using HeuristicLab.Core; using HeuristicLab.Random; /// /// The basic data block of a Skip List /// class SkipListNode : IDisposable where T : IComparable { private T value; private SkipListNode next; private SkipListNode previous; private SkipListNode above; private SkipListNode below; public virtual T Value { get { return value; } set { this.value = value; } } public virtual SkipListNode Next { get { return next; } set { next = value; } } public virtual SkipListNode Previous { get { return previous; } set { previous = value; } } public virtual SkipListNode Above { get { return above; } set { above = value; } } public virtual SkipListNode Below { get { return below; } set { below = value; } } public SkipListNode(T value) { Value = value; } public void Dispose() { value = default(T); next = null; previous = null; above = null; previous = null; } public virtual bool IsHeader() { return GetType() == typeof(SkipListNodeHeader); } public virtual bool IsFooter() { return GetType() == typeof(SkipListNodeFooter); } } /// /// Represents a Skip List node that is the header of a level /// class SkipListNodeHeader : SkipListNode where T : IComparable { public SkipListNodeHeader() : base(default(T)) { } } /// /// Represents a Skip List node that is the footer of a level /// class SkipListNodeFooter : SkipListNode where T : IComparable { public SkipListNodeFooter() : base(default(T)) { } } class SkipList : ICollection where T : IComparable { internal SkipListNode topLeft; internal SkipListNode bottomLeft; internal IRandom random; private int levels; private int size; private int maxLevels = int.MaxValue; public virtual int Levels { get { return levels; } } public virtual int MaxLevels { get { return maxLevels; } set { maxLevels = value; } } public virtual int Count { get { return size; } } public virtual bool IsReadOnly { get { return false; } } public virtual SkipListNode Head { get { return bottomLeft; } } public SkipList(IRandom random = null) { topLeft = getEmptyLevel(); //create an empty level bottomLeft = topLeft; levels = 1; //update the level count size = 0; //no elements added this.random = random ?? new FastRandom(); //used for adding new values } /// /// Creates an empty level with a header and footer node /// protected SkipListNode getEmptyLevel() { SkipListNode negativeInfinity = new SkipListNodeHeader(); SkipListNode positiveInfinity = new SkipListNodeFooter(); negativeInfinity.Next = positiveInfinity; positiveInfinity.Previous = negativeInfinity; return negativeInfinity; } /// /// Randomly determines how many levels to add /// protected int getRandomLevels() { int newLevels = 0; while (random.Next(0, 2) == 1 && newLevels < maxLevels) //1 is heads, 0 is tails { newLevels++; } return newLevels; } /// /// Removes all the empty levels leftover in the Skip List /// protected void clearEmptyLevels() { if (levels > 1) //more than one level, don't want to remove bottom level { SkipListNode currentNode = topLeft; while (currentNode != bottomLeft) //do not remove the bottom level { if (currentNode.IsHeader() && currentNode.Next.IsFooter()) { SkipListNode belowNode = currentNode.Below; //Remove the empty level //Update pointers topLeft = currentNode.Below; //Remove links currentNode.Next.Dispose(); currentNode.Dispose(); //Update counters levels--; currentNode = belowNode; //scan down } else break; //a single non-emtpy level means the rest of the levels are not empty } } } /// /// Add a value to the Skip List /// public virtual void Add(T value) { int valueLevels = getRandomLevels(); //determine height of value's tower //Add levels to entire list if necessary int newLevelCount = valueLevels - levels; //number of levels missing while (newLevelCount > 0) { //Create new level SkipListNode newLevel = getEmptyLevel(); //Link down newLevel.Below = topLeft; topLeft.Above = newLevel; topLeft = newLevel; //update reference to most top-left node //Update counters newLevelCount--; levels++; } //Insert the value in the proper position, creating as many levels as was randomly determined SkipListNode currentNode = topLeft; SkipListNode lastNodeAbove = null; //keeps track of the upper-level nodes in a tower int currentLevel = levels - 1; while (currentLevel >= 0 && currentNode != null) { if (currentLevel > valueLevels) //too high on the list, nothing would be added to this level { currentNode = currentNode.Below; //scan down currentLevel--; //going one level lower continue; //skip adding to this level } //Add the value to the current level //Find the biggest value on the current level that is less than the value to be added while (currentNode.Next != null) { if (!currentNode.Next.IsFooter() && currentNode.Next.Value.CompareTo(value) < 0) //smaller currentNode = currentNode.Next; //keep scanning across else break; //the next node would be bigger than the value } //Insert the value right after the node found SkipListNode newNode = new SkipListNode(value); newNode.Next = currentNode.Next; newNode.Previous = currentNode; newNode.Next.Previous = newNode; currentNode.Next = newNode; //Link down/up the tower if (lastNodeAbove != null) //is this node part of a tower? { lastNodeAbove.Below = newNode; newNode.Above = lastNodeAbove; } lastNodeAbove = newNode; //start/continue tower //Scan down currentNode = currentNode.Below; currentLevel--; } size++; //update count } /// /// Returns the first node whose value matches the input value /// public virtual SkipListNode Find(T value) { SkipListNode foundNode = topLeft; //Look for the highest-level node with an element value matching the parameter value while (foundNode != null && foundNode.Next != null) { if (!foundNode.Next.IsFooter() && foundNode.Next.Value.CompareTo(value) < 0) //next node's value is still smaller foundNode = foundNode.Next; //keep scanning across else { if (!foundNode.Next.IsFooter() && foundNode.Next.Value.Equals(value)) //value found { foundNode = foundNode.Next; break; } else foundNode = foundNode.Below; //element not in this level, scan down } } return foundNode; } /// /// Returns the lowest node on the first tower to match the input value /// public virtual SkipListNode FindLowest(T value) { SkipListNode valueNode = Find(value); return FindLowest(valueNode); } /// /// Returns the lowest node on the first tower to match the input value /// public virtual SkipListNode FindLowest(SkipListNode valueNode) { if (valueNode == null) return null; else { //Scan down to the lowest level while (valueNode.Below != null) { valueNode = valueNode.Below; } return valueNode; } } /// /// Returns the highest node on the first tower to match the input value /// public virtual SkipListNode FindHighest(T value) { SkipListNode valueNode = Find(value); return FindHighest(valueNode); } /// /// Returns the highest node on the first tower to match the input value /// public virtual SkipListNode FindHighest(SkipListNode valueNode) { if (valueNode == null) return null; else { //Scan up to the highest level while (valueNode.Above != null) { valueNode = valueNode.Above; } return valueNode; } } /// /// Returns whether a value exists in the Skip List /// public virtual bool Contains(T value) { return (Find(value) != null); } /// /// Removes a value or node from the Skip List /// public virtual bool Remove(T value) { SkipListNode valueNode = FindHighest(value); return Remove(valueNode); } /// /// Removes a value or node from the Skip List /// public virtual bool Remove(SkipListNode valueNode) { if (valueNode == null) return false; else { //Make sure node is top-level node in it's tower if (valueNode.Above != null) valueNode = FindHighest(valueNode); //---Delete nodes going down the tower SkipListNode currentNodeDown = valueNode; while (currentNodeDown != null) { //Remove right-left links SkipListNode previousNode = currentNodeDown.Previous; SkipListNode nextNode = currentNodeDown.Next; //Link the previous and next nodes to each other previousNode.Next = nextNode; nextNode.Previous = previousNode; SkipListNode belowNode = currentNodeDown.Below; //scan down currentNodeDown.Dispose(); //unlink previous currentNodeDown = belowNode; } //update counter size--; //Clean up the Skip List by removing levels that are now empty clearEmptyLevels(); return true; } } /// /// Removes all values in the Skip List /// public virtual void Clear() { SkipListNode currentNode = Head; while (currentNode != null) { SkipListNode nextNode = currentNode.Next; //save reference to next node if (!currentNode.IsHeader() && !currentNode.IsFooter()) { Remove(currentNode); } currentNode = nextNode; } } /// /// Copies the values of the Skip List to an array /// public virtual void CopyTo(T[] array) { CopyTo(array, 0); } /// /// Copies the values of the Skip List to an array /// public virtual void CopyTo(T[] array, int startIndex) { IEnumerator enumerator = GetEnumerator(); for (int i = startIndex; i < array.Length; i++) { if (enumerator.MoveNext()) array[i] = enumerator.Current; else break; } } /// /// Gets the number of levels of a value in the Skip List /// public virtual int GetHeight(T value) { SkipListNode valueNode = FindLowest(value); return GetHeight(valueNode); } /// /// Gets the number of levels of a value in the Skip List /// public virtual int GetHeight(SkipListNode valueNode) { int height = 0; SkipListNode currentNode = valueNode; //Move all the way down to the bottom first while (currentNode.Below != null) { currentNode = currentNode.Below; } //ExpressionCount going back up to the top while (currentNode != null) { height++; currentNode = currentNode.Above; } return height; } /// /// Gets the enumerator for the Skip List /// public IEnumerator GetEnumerator() { return new SkipListEnumerator(this); } /// /// Gets the enumerator for the Skip List /// IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// Enumerator for a Skip List. Scans across the lowest level of a Skip List. /// internal class SkipListEnumerator : IEnumerator { private SkipListNode current; private SkipList skipList; public SkipListEnumerator(SkipList skipList) { this.skipList = skipList; } public T Current { get { return current.Value; } } object IEnumerator.Current { get { return Current; } } public void Dispose() { current = null; } public void Reset() { current = null; } public bool MoveNext() { if (current == null) current = skipList.Head.Next; //Head is header node, start after else current = current.Next; if (current != null && current.IsFooter()) current = null; //end of list return (current != null); } } } }