Mega Code Archive

 
Categories / C# / Collections Data Structure
 

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 définissant 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 implémentation 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">début 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>         /// Vérifie que les données de la pile sont cohérentes         /// </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 élément         /// </summary>         /// <param name="key">élement dont on veut changer la priorité</param>         /// <param name="priority">nouvelle prioritée</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>         /// Enumérateur 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     } }