#region CPL License /* Nuclex Framework Copyright (C) 2002-2008 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using System.Collections; namespace Nuclex.Support.Collections { /// Queue that dequeues items in order of their priority public class PriorityQueue : ICollection, IEnumerable { #region class Enumerator /// Enumerates all items contained in a priority queue private class Enumerator : IEnumerator { /// Initializes a new priority queue enumerator /// Priority queue to be enumerated public Enumerator(PriorityQueue priorityQueue) { this.priorityQueue = priorityQueue; Reset(); } /// Resets the enumerator to its initial state public void Reset() { index = -1; version = priorityQueue.version; } /// The current item being enumerated ItemType IEnumerator.Current { get { checkVersion(); return priorityQueue.heap[index]; } } /// Moves to the next item in the priority queue /// True if a next item was found, false if the end has been reached public bool MoveNext() { checkVersion(); if(index + 1 == priorityQueue.count) return false; ++index; return true; } /// Releases all resources used by the enumerator public void Dispose() { } /// Ensures that the priority queue has not changed private void checkVersion() { if(version != priorityQueue.version) throw new InvalidOperationException("Priority queue has been modified"); } /// The current item being enumerated object IEnumerator.Current { get { checkVersion(); return priorityQueue.heap[index]; } } /// Index of the current item in the priority queue private int index; /// The priority queue whose items this instance enumerates private PriorityQueue priorityQueue; /// Expected version of the priority queue private int version; } #endregion // class Enumerator /// /// Initializes a new priority queue using IComparable for comparing items /// public PriorityQueue() : this(Comparer.Default) { } /// Initializes a new priority queue /// Comparer to use for ordering the items public PriorityQueue(IComparer comparer) { this.comparer = comparer; this.capacity = 15; // 15 is equal to 4 complete levels this.heap = new ItemType[this.capacity]; } /// Returns the topmost item in the queue without dequeueing it /// The topmost item in the queue public ItemType Peek() { if(this.count == 0) { throw new InvalidOperationException("No items queued"); } return this.heap[0]; } /// Takes the item with the highest priority off from the queue /// The item with the highest priority in the list /// When the queue is empty public ItemType Dequeue() { if(this.count == 0) { throw new InvalidOperationException("No items available to dequeue"); } ItemType result = this.heap[0]; --this.count; trickleDown(0, this.heap[this.count]); ++this.version; return result; } /// Puts an item into the priority queue /// Item to be queued public void Enqueue(ItemType item) { if(this.count == capacity) growHeap(); ++this.count; bubbleUp(this.count - 1, item); ++this.version; } /// Removes all items from the priority queue public void Clear() { this.count = 0; ++this.version; } /// Total number of items in the priority queue public int Count { get { return this.count; } } /// Copies the contents of the priority queue into an array /// Array to copy the priority queue into /// Starting index for the destination array public void CopyTo(Array array, int index) { Array.Copy(this.heap, 0, array, index, this.count); } /// /// Obtains an object that can be used to synchronize accesses to the priority queue /// from different threads /// public object SyncRoot { get { return this; } } /// Whether operations performed on this priority queue are thread safe public bool IsSynchronized { get { return false; } } /// Returns a typesafe enumerator for the priority queue /// A new enumerator for the priority queue public IEnumerator GetEnumerator() { return new Enumerator(this); } /// Moves an item upwards in the heap tree /// Index of the item to be moved /// Item to be moved private void bubbleUp(int index, ItemType item) { int parent = getParent(index); // Note: (index > 0) means there is a parent while((index > 0) && (this.comparer.Compare(this.heap[parent], item) < 0)) { this.heap[index] = this.heap[parent]; index = parent; parent = getParent(index); } this.heap[index] = item; } /// Move the item downwards in the heap tree /// Index of the item to be moved /// Item to be moved private void trickleDown(int index, ItemType item) { int child = getLeftChild(index); while(child < this.count) { bool needsToBeMoved = ((child + 1) < this.count) && (this.comparer.Compare(heap[child], this.heap[child + 1]) < 0); if(needsToBeMoved) ++child; this.heap[index] = this.heap[child]; index = child; child = getLeftChild(index); } bubbleUp(index, item); } /// Obtains the left child item in the heap tree /// Index of the item whose left child to return /// The left child item of the provided parent item private int getLeftChild(int index) { return (index * 2) + 1; } /// Calculates the parent entry of the item on the heap /// Index of the item whose parent to calculate /// The index of the parent to the specified item private int getParent(int index) { return (index - 1) / 2; } /// Increases the size of the priority collection's heap private void growHeap() { this.capacity = (capacity * 2) + 1; ItemType[] newHeap = new ItemType[this.capacity]; Array.Copy(this.heap, 0, newHeap, 0, this.count); this.heap = newHeap; } /// Returns an enumerator for the priority queue /// A new enumerator for the priority queue IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); } /// Comparer used to order the items in the priority queue private IComparer comparer; /// Total number of items in the priority queue private int count; /// Available space in the priority queue private int capacity; /// Incremented whenever the priority queue is modified private int version; /// Tree containing the items in the priority queue private ItemType[] heap; } } // namespace Nuclex.Support.Collections