/// <summary> /// Removes a node from the queue. The node does not need to be the head of the /// queue. This is an O(log n) operation. /// </summary> /// public void Remove(PriorityQueueNode <T> node) { #if DEBUG if (!Contains(node)) { throw new InvalidOperationException("Cannot call Remove() on a node which is not enqueued: " + node); } #endif CheckQueue(); // If the node is already the last node, we can remove it immediately if (node.QueueIndex == numberOfNodes) { nodes[numberOfNodes] = PriorityQueueNode <T> .Empty; numberOfNodes--; return; } int index = node.QueueIndex; // Swap the node with the last node swap(node.QueueIndex, numberOfNodes); nodes[numberOfNodes] = PriorityQueueNode <T> .Empty; numberOfNodes--; // Now bubble formerLastNode (which is no longer the last node) up or down as appropriate OnNodeUpdated(ref nodes[index]); CheckQueue(); }
/// <summary> /// Compares the current object with another object of the same type. /// </summary> /// <param name="other">An object to compare with this object.</param> /// <returns> /// A value that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other" /> parameter.Zero This object is equal to <paramref name="other" />. Greater than zero This object is greater than <paramref name="other" />. /// </returns> public int CompareTo(PriorityQueueNode <T> other) { int order = this.Priority.CompareTo(other.Priority); if (order == 0) { order = this.InsertionIndex.CompareTo(other.InsertionIndex); } return(order); }
public bool Contains(PriorityQueueNode <T> node) { #if DEBUG if (node.QueueIndex < 0 || node.QueueIndex >= nodes.Length) { throw new InvalidOperationException("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?"); } #endif return(nodes[node.QueueIndex] == node); }
public void UpdatePriority(ref PriorityQueueNode <T> node, double priority) { #if DEBUG if (!Contains(node)) { throw new InvalidOperationException("Cannot call UpdatePriority() on a node which is not enqueued: " + node); } #endif node.Priority = priority; OnNodeUpdated(ref node); }
/// <summary> /// Returns an array containing the items in this list, /// optionally in in priority order. /// </summary> /// /// <param name="sorted">Whether to return the items in priority order.</param> /// public PriorityQueueNode <T>[] ToArray(bool sorted = true) { var result = new PriorityQueueNode <T> [numberOfNodes]; for (int i = 0; i < result.Length; i++) { result[i] = nodes[i + 1]; } if (sorted) { Array.Sort(result); } return(result); }
private void OnNodeUpdated(ref PriorityQueueNode <T> node) { // Bubble the updated node up or down as appropriate int parentIndex = node.QueueIndex / 2; if (parentIndex > 0 && HasHigherPriority(node.QueueIndex, parentIndex)) { cascadeUp(ref node); } else { cascadeDown(ref node); } }
public PriorityQueueNode <T> Enqueue(T value, double priority) { CheckQueue(); numberOfNodes++; if (numberOfNodes >= nodes.Length) { Resize(nodes.Length + (int)(0.1 * nodes.Length)); } var node = new PriorityQueueNode <T>(value, priority, numberOfNodes, counter++); nodes[numberOfNodes] = node; cascadeUp(ref nodes[numberOfNodes]); CheckQueue(); return(node); }
private void cascadeDown(ref PriorityQueueNode <T> node) { // aka Heapify-down int newParent; int finalQueueIndex = node.QueueIndex; while (true) { newParent = nodes[finalQueueIndex].QueueIndex; int childLeftIndex = 2 * finalQueueIndex; // Check if the left-child is higher-priority than the current node if (childLeftIndex > numberOfNodes) { break; } if (HasHigherPriority(childLeftIndex, newParent)) { newParent = childLeftIndex; } // Check if the right-child is higher-priority than either the current node or the left child int childRightIndex = childLeftIndex + 1; if (childRightIndex <= numberOfNodes) { if (HasHigherPriority(childRightIndex, newParent)) { newParent = childRightIndex; } } // If either of the children has higher (smaller) priority, swap and continue cascading if (newParent != finalQueueIndex) { swap(finalQueueIndex, newParent); finalQueueIndex = newParent; } else { break; } } }
private void cascadeUp(ref PriorityQueueNode <T> node) { // aka Heapify-up int current = node.QueueIndex; int parent = node.QueueIndex / 2; while (parent >= 1) { if (HasHigherPriority(parent, current)) { break; } // Node has lower priority value, so move it up the heap swap(current, parent); current = nodes[parent].QueueIndex; parent = current / 2; } }
/// <summary> /// Resize the queue so it can accept more nodes. All currently enqueued nodes are kept. /// Attempting to decrease the queue size to a size too small to hold the existing nodes /// results in undefined behavior. This is an O(n) operation. /// </summary> /// public void Resize(int capacity) { #if DEBUG if (capacity <= 0) { throw new InvalidOperationException("Queue size cannot be smaller than 1"); } if (capacity < numberOfNodes) { throw new InvalidOperationException("Called Resize(" + capacity + "), but current queue contains " + numberOfNodes + " nodes"); } #endif var newArray = new PriorityQueueNode <T> [capacity + 1]; int highestIndexToCopy = Math.Min(capacity, numberOfNodes); for (int i = 1; i <= highestIndexToCopy; i++) { newArray[i] = nodes[i]; } nodes = newArray; }
/// <summary> /// Indicates whether the current object is equal to another object of the same type. /// </summary> /// <param name="other">An object to compare with this object.</param> /// <returns> /// true if the current object is equal to the <paramref name="other" /> parameter; otherwise, false. /// </returns> public bool Equals(PriorityQueueNode <T> other) { return(Value.Equals(other.value)); }