Priority Queue
/*== == Copyright : BlueCurve (c) == Licence : Gnu/GPL v2.x == Author : Teddy Albina == Email : bluecurveteam@gmail.com == Web site : http://www.codeplex.com/BlueCurve */ using System; using BlueCurve.Search.Common; using System.Collections; using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; namespace BlueCurve.Search.Common.PriorityQueue { /// <summary> /// Struct dfinissant un PriorityQueueItem /// </summary> /// <typeparam name="TValue">Clef</typeparam> /// <typeparam name="TPriority">Valeur</typeparam> [Serializable] public struct PriorityQueueItem<TValue, TPriority> { private TValue _value; public TValue Value { get { return _value; } set { _value = value; } } private TPriority _priority; public TPriority Priority { get { return _priority; } set { _priority = value; } } internal PriorityQueueItem(TValue val, TPriority pri) { this._value = val; this._priority = pri; } } /// <summary> /// Fournit une implmentation de priorityQueue /// </summary> /// <typeparam name="TValue">Type de clef</typeparam> /// <typeparam name="TPriority">Type de valeur</typeparam> [Serializable] public class PriorityQueue<TValue, TPriority> : ICollection , IEnumerable<PriorityQueueItem<TValue, TPriority>> { /// <summary> /// This features enable the priority queue to increment automaticaly /// the priority of the item /// </summary> private PriorityQueueItem<TValue, TPriority>[] items; /// <summary> /// Default capacity of the queue /// </summary> private const Int32 DefaultCapacity = 1024; /// <summary> /// Capacity of the queue /// </summary> private Int32 capacity; /// <summary> /// Numbers of items in the queue /// </summary> private Int32 numItems; /// <summary> /// Comparison delegate /// </summary> private Comparison<TPriority> compareFunc; /// <summary> /// Initializes a new instance of the PriorityQueue class that is empty, /// has the default initial capacity, and uses the default IComparer. /// </summary> public PriorityQueue() : this(DefaultCapacity, Comparer<TPriority>.Default) { } public PriorityQueue(Int32 initialCapacity) : this(initialCapacity, Comparer<TPriority>.Default) { } public PriorityQueue(IComparer<TPriority> comparer) : this(DefaultCapacity, comparer) { } public PriorityQueue(int initialCapacity, IComparer<TPriority> comparer) { Init(initialCapacity, new Comparison<TPriority>(comparer.Compare)); } public PriorityQueue(Comparison<TPriority> comparison) : this(DefaultCapacity, comparison) { } public PriorityQueue(int initialCapacity, Comparison<TPriority> comparison) { Init(initialCapacity, comparison); } private void Init(int initialCapacity, Comparison<TPriority> comparison) { numItems = 0; compareFunc = comparison; SetCapacity(initialCapacity); } public int Count { get { return numItems; } } public int Capacity { get { return items.Length; } set { SetCapacity(value); } } private void SetCapacity(int newCapacity) { int newCap = newCapacity; if (newCap < DefaultCapacity) newCap = DefaultCapacity; // throw exception if newCapacity < NumItems if (newCap < numItems) throw new ArgumentOutOfRangeException("newCapacity", "New capacity is less than Count"); this.capacity = newCap; if (items == null) { items = new PriorityQueueItem<TValue, TPriority>[newCap]; return; } // Resize the array. Array.Resize<PriorityQueueItem<TValue, TPriority>>(ref items, newCap); } public void Enqueue(PriorityQueueItem<TValue, TPriority> newItem) { if (numItems == capacity) { // need to increase capacity // grow by 50 percent SetCapacity((3 * Capacity) / 2); } int i = numItems; ++numItems; while ((i > 0) && (compareFunc(items[(i - 1) / 2].Priority, newItem.Priority) < 0)) { items[i] = items[(i - 1) / 2]; i = (i - 1) / 2; } items[i] = newItem; } /// <summary> /// Permet d'ajouter des elements dans la pile /// </summary> /// <param name="value">Clef</param> /// <param name="priority">Priorit</param> public void Enqueue(TValue value, TPriority priority) { Enqueue(new PriorityQueueItem<TValue, TPriority>(value, priority)); } /// <summary> /// Permet de supprimer un intervale de la file d'attente /// </summary> /// <param name="index">dbut de l'intervalle</param> /// <returns>PriorityQueueItem</returns> private PriorityQueueItem<TValue, TPriority> RemoveAt(Int32 index) { PriorityQueueItem<TValue, TPriority> o = items[index]; --numItems; // move the last item to fill the hole PriorityQueueItem<TValue, TPriority> tmp = items[numItems]; // If you forget to clear this, you have a potential memory leak. items[numItems] = default(PriorityQueueItem<TValue, TPriority>); if (numItems > 0 && index != numItems) { // If the new item is greater than its parent, bubble up. int i = index; int parent = (i - 1) / 2; while (compareFunc(tmp.Priority, items[parent].Priority) > 0) { items[i] = items[parent]; i = parent; parent = (i - 1) / 2; } // if i == index, then we didn't move the item up if (i == index) { // bubble down ... while (i < (numItems) / 2) { int j = (2 * i) + 1; if ((j < numItems - 1) && (compareFunc(items[j].Priority, items[j + 1].Priority) < 0)) ++j; if (compareFunc(items[j].Priority, tmp.Priority) <= 0) break; items[i] = items[j]; i = j; } } // Be sure to store the item in its place. items[i] = tmp; } return o; } /// <summary> /// Vrifie que les donnes de la pile sont cohrentes /// </summary> /// <returns>bool</returns> public bool VerifyQueue() { int i = 0; while (i < numItems / 2) { int leftChild = (2 * i) + 1; int rightChild = leftChild + 1; if (compareFunc(items[i].Priority, items[leftChild].Priority) < 0) return false; if (rightChild < numItems && compareFunc(items[i].Priority, items[rightChild].Priority) < 0) return false; ++i; } return true; } /// <summary> /// Permet d'obtenir un lement /// </summary> /// <returns>PriorityQueueItem</returns> public PriorityQueueItem<TValue, TPriority> Dequeue() { if (Count == 0) throw new InvalidOperationException("The queue is empty"); return RemoveAt(0); } /// <summary> /// Removes the item with the specified value from the queue. /// The passed equality comparison is used. /// </summary> /// <param name="item">The item to be removed.</param> /// <param name="comparer">An object that implements the IEqualityComparer interface /// for the type of item in the collection.</param> public void Remove(TValue item, IEqualityComparer comparer) { // need to find the PriorityQueueItem that has the Data value of o for (int index = 0; index < numItems; ++index) { if (comparer.Equals(item, items[index].Value)) { RemoveAt(index); return; } } throw new ApplicationException("The specified itemm is not in the queue."); } /// <summary> /// Removes the item with the specified value from the queue. /// The default type comparison function is used. /// </summary> /// <param name="item">The item to be removed.</param> public void Remove(TValue item) { Remove(item, EqualityComparer<TValue>.Default); } /// <summary> /// Permet d'obtenir le premier lement de la pile /// </summary> /// <returns>PriorityQueueItem</returns> public PriorityQueueItem<TValue, TPriority> Peek() { if (Count == 0) throw new InvalidOperationException("The queue is empty"); return items[0]; } /// <summary> /// Permet de vider la pile /// </summary> public void Clear() { for (int i = 0; i < numItems; ++i) { items[i] = default(PriorityQueueItem<TValue, TPriority>); } numItems = 0; TrimExcess(); } /// <summary> /// Set the capacity to the actual number of items, if the current /// number of items is less than 90 percent of the current capacity. /// </summary> public void TrimExcess() { if (numItems < (float)0.9 * capacity) { SetCapacity(numItems); } } /// <summary> /// Permet de savoir si un lement existe dans la pile /// </summary> /// <param name="o">element a tester</param> /// <returns>bool</returns> public bool Contains(TValue o) { foreach (PriorityQueueItem<TValue, TPriority> x in items) { if (x.Value.Equals(o)) return true; } return false; } /// <summary> /// Permet d'obtenir la priorit d'un element /// </summary> /// <param name="key">element dont on veut la priorit</param> /// <returns>TPriority</returns> public TPriority GetPriority(TValue key) { foreach (PriorityQueueItem<TValue, TPriority> x in items) { if (x.Value.Equals(key)) return x.Priority; } return default(TPriority); } /// <summary> /// Permet de changer la priorit d'un lment /// </summary> /// <param name="key">lement dont on veut changer la priorit</param> /// <param name="priority">nouvelle priorite</param> /// <returns>bool</returns> public bool SetPriority(TValue key, TPriority priority) { for (int i = 0; i < items.Length; i++) { PriorityQueueItem<TValue, TPriority> x = items[i]; if (x.Value.Equals(key)) { Console.WriteLine(x.Value); items[i].Priority = priority; return true; } } return false; } /// <summary> /// Permet de copier les lements de la pile dans un PriorityQueueItem /// </summary> /// <param name="array">PriorityQueueItem</param> /// <param name="arrayIndex">index de l'array a copier</param> public void CopyTo(PriorityQueueItem<TValue, TPriority>[] array, int arrayIndex) { if (array == null) throw new ArgumentNullException("array"); if (arrayIndex < 0) throw new ArgumentOutOfRangeException("arrayIndex", "arrayIndex is less than 0."); if (array.Rank > 1) throw new ArgumentException("array is multidimensional."); if (numItems == 0) return; if (arrayIndex >= array.Length) throw new ArgumentException("arrayIndex is equal to or greater than the length of the array."); if (numItems > (array.Length - arrayIndex)) throw new ArgumentException("The number of elements in the source ICollection is greater than the available space from arrayIndex to the end of the destination array."); for (int i = 0; i < numItems; i++) { array[arrayIndex + i] = items[i]; } } #region ICollection Members /// <summary> /// Permet de copier a partir d'un Array /// </summary> /// <param name="array">pile source</param> /// <param name="index">index source</param> public void CopyTo(Array array, int index) { this.CopyTo((PriorityQueueItem<TValue, TPriority>[])array, index); } public bool IsSynchronized { get { return false; } } public object SyncRoot { get { return items.SyncRoot; } } #endregion #region IEnumerable<PriorityQueueItem<TValue,TPriority>> Members /// <summary> /// Enumrateur de la pile /// </summary> /// <returns>IEnumerator</returns> public IEnumerator<PriorityQueueItem<TValue, TPriority>> GetEnumerator() { for (int i = 0; i < numItems; i++) { yield return items[i]; } } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region 'Save' /// <summary> /// Permet de sauvegarder la pile /// </summary> /// <returns>bool</returns> public bool Save () { try { using (Stream stream = File.Open("QueuePriority.bin", FileMode.Create, FileAccess.Write, FileShare.None)) { BinaryFormatter formatter = new BinaryFormatter(); formatter.Serialize(stream, items); stream.Close(); stream.Dispose(); } return true; } catch { return false; } } /// <summary> /// Permet de restaures la pile de priorit /// </summary> /// <returns></returns> public bool Reload() { PriorityQueueItem<TValue, TPriority>[] temp; try { using (Stream stream = File.Open("QueuePriority.bin", FileMode.Open, FileAccess.Read, FileShare.None)) { BinaryFormatter formatter = new BinaryFormatter(); temp = (PriorityQueueItem<TValue, TPriority>[])formatter.Deserialize(stream); stream.Close(); stream.Dispose(); } if (temp.Length > 0) items = (PriorityQueueItem<TValue, TPriority>[])temp.Clone(); return true; } catch { return false; } } #endregion } }