Mega Code Archive

 
Categories / C# / Collections Data Structure
 

Priority Queue (2)

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SQLToolbox.Lib {   /// <summary>   /// Represents a strongly typed priority queue of objects.    /// Objects are ordered in the priority queue according to the provided ordering comparator    /// (from smallest to largest) and not by the order of the insertion as in the regular queue.   /// Provides methods to add(enqueue) and remove(dequeue) object from ordered queue.    /// </summary>   /// <remarks> PriorityQueue(Of T) is implemented on the basis of List(Of T) and intentionally does not    /// hide base class functions that can possibly invalidate the queue ordering. After operations    /// that manipulates with list objects of the list itself (adding/removing) You have to restore queue    /// ordering by using AdjustHeap methods.</remarks>   public class PriorityQueue<T> : List<T>   {     /// <summary>     /// Initializes a new instance of the PriorityQueue class that is empty,      /// has the default initial capacity, default comparator for the items.     /// </summary>     public PriorityQueue()     {       comparer = Comparer<T>.Default;     }     /// <summary>     /// Initializes a new instance of the PriorityQueue class that is empty,      /// has the default initial capacity, and uses the specified IComparer.      /// </summary>     /// <param name="comparer">The IComparer implementation to use when comparing items.</param>     public PriorityQueue(IComparer<T> comparer)     {       this.comparer = comparer;     }     /// <summary>     /// Initializes a new instance of the PriorityQueue class that is empty,      /// has the specified initial capacity and default comparator for the items.             /// </summary>     /// <param name="capacity">The initial number of elements that the queue can contain.</param>     public PriorityQueue(int capacity)       : base(capacity)     {       comparer = Comparer<T>.Default;     }     /// <summary>     /// Initializes a new instance of the PriorityQueue class that is empty,      /// has the specified initial capacity and comparator for the items.             /// </summary>     /// <param name="capacity">The initial number of elements that the queue can contain.</param>     /// <param name="comparer">The IComparer implementation to use when comparing items.</param>     public PriorityQueue(int capacity, IComparer<T> comparer)       : base(capacity)     {       this.comparer = comparer;     }     /// <summary>     /// Returns the the smallest (first) object of the Queue without removing it.      /// </summary>     /// <returns>The object at the beginning of the Queue.</returns>     public T Peek()     {       return this[0];     }     /// <summary>     /// Adds an object to the Priority Queue.      /// </summary>     /// <param name="item">The object to add to the Queue.</param>     public void Enqueue(T item)     {       Add(item);       AdjustHeap(Count - 1);     }     /// <summary>     /// Adds the elements of an ICollection to queue.      /// </summary>     /// <param name="collection">The ICollection whose elements should be added to the queue</param>     public void EnqueueRange(IEnumerable<T> collection)     {       int pcount = Count;       AddRange(collection);       AdjustHeap(pcount, Count - pcount);     }     /// <summary>     /// Removes and returns the smallest object of the Queue.      /// </summary>     /// <returns>The smallest object that is removed from the beginning of the Queue. </returns>     public T Dequeue()     {       int last = Count - 1;       swap(0, last);       T res = this[last];       this.RemoveAt(last);       AdjustHeap(0);       return res;     }     /// <summary>     /// Rebuild heap after change of one heap element     /// </summary>     /// <param name="position">Position of changed item</param>     public void AdjustHeap(int position)     {       int up = position;       while (up > 0)       {         int parent = (up - 1) / 2;         if (comparer.Compare(this[parent], this[up]) <= 0)           break;         swap(parent, up);         up = parent;       }       if (up != position)         return;       int down = position;       while (down * 2 + 1 < Count)       {         int child = down * 2 + 1;         if (child + 1 < Count &&           comparer.Compare(this[child + 1], this[child]) <= 0)           child++;         if (comparer.Compare(this[down], this[child]) <= 0)           break;         swap(child, down);         down = child;       }     }     /// <summary>     /// Rebuild heap structure of the list after change of element range     /// </summary>     /// <remarks>Can be used to restore heap structure of the Priority Queue after changes were      /// made to part of the underlying array</remarks>     public void AdjustHeap(int from, int count)     {       for (int i = 0; i < count; ++i)         AdjustHeap(from + i);     }     /// <summary>     /// Rebuild heap structure of the changed list     /// </summary>     /// <remarks>Can be used to restore heap structure of the Priority Queue after changes were      /// made to underlying array</remarks>     public void AdjustHeap()     {       AdjustHeap(0, (Count + 1) / 2);     }     private void swap(int i, int j)     {       T t = this[i];       this[i] = this[j];       this[j] = t;     }     private readonly IComparer<T> comparer;     /// <summary>     /// Gets the IComparer for the queue.      /// </summary>     public IComparer<T> Comparer     {       get { return comparer; }     }   } } /* using System; using System.Collections.Generic; using System.Linq; using System.Text; using NUnit.Framework; //documentation warning - no need to document unit tests #pragma warning disable 1591 namespace SQLToolbox.Lib.UnitTests {   /// <summary>   /// Write the summary for the test class here.   /// </summary>   [TestFixture]   public class PriorityQueueTest   {     public bool peek_checkPQ<T>(PriorityQueue<T> pq)     {       IComparer<T> c = pq.Comparer;       for (int i = 0; i < pq.Count; i++)       {         int child = 2 * i + 1;         if (child >= pq.Count)           break;         if (c.Compare(pq[i], pq[child]) > 0)           return false;         ++child;         if (child >= pq.Count)           break;         if (c.Compare(pq[i], pq[child]) > 0)           return false;       }       return true;     }     public bool pop_checkPQ<T>(PriorityQueue<T> pq)     {       IComparer<T> c = pq.Comparer;       while (pq.Count > 1)       {         T pop = pq.Dequeue();         if (c.Compare(pop, pq.Peek()) > 0)           return false;       }       return true;     }     public bool pop_fullcheckPQ<T>(PriorityQueue<T> pq)     {       IComparer<T> c = pq.Comparer;       while (pq.Count > 1)       {         T pop = pq.Dequeue();         for (int i = 0; i < pq.Count; ++i)         {           if (c.Compare(pop, pq[i]) > 0)             return false;         }       }       return true;     }     public class abscomparer : IComparer<int>     {       public int Compare(int x, int y)       {         return Math.Abs(x) - Math.Abs(y);       }     }     [Test]     public void p1()     {       PriorityQueue<int> pq = new PriorityQueue<int>(new abscomparer());       int s = 0;       pq.Enqueue(3); s++;       pq.Enqueue(2); s++;       pq.Enqueue(2); s++;       pq.Enqueue(4); s++;       pq.Enqueue(1); s++;       pq.Enqueue(-5); s++;       pq.Enqueue(-3); s++;       pq.Sort(new abscomparer());       pq.AdjustHeap();       pq.Sort();       pq.AdjustHeap();       pq.EnqueueRange(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });       s += 10;       Assert.AreEqual(s, pq.Count);       Assert.IsTrue(pq.Contains(2));       Assert.IsTrue(pq.Contains(4));       Assert.IsTrue(pq.Contains(-5));       Assert.AreEqual(0, pq.IndexOf(1));       Assert.IsTrue(peek_checkPQ(pq));       Assert.IsTrue(pop_fullcheckPQ(pq));     }     [Test]     public void longRandomTest()     {       for (int longloop = 0; longloop < 2; longloop++)       {         PriorityQueue<int> pq = new PriorityQueue<int>();         Random rnd = new Random();         int num = rnd.Next(2000, 4000);         for (int i = 0; i < num; ++i)           pq.Enqueue(rnd.Next(-1000, 1000));         Assert.AreEqual(num, pq.Count);         Assert.IsTrue(peek_checkPQ(pq));         Assert.AreEqual(num, pq.Count);         Assert.IsTrue(pop_checkPQ(pq));         //System.Diagnostics.Trace.WriteLine("loop:" + longloop.ToString());       }     }     [Test]     public void DynamicTest()     {       PriorityQueue<int> pq = new PriorityQueue<int>();       Random rnd = new Random();       int num = rnd.Next(1000);       for (int i = 0; i < num; ++i)         pq.Enqueue(rnd.Next(-1000, 1000));       for (int i = 0; i < 1000; ++i)       {         pq.Enqueue(rnd.Next(-1000, 1000));         int pop = pq.Dequeue();         Assert.IsTrue(pop <= pq.Peek());         Assert.AreEqual(num, pq.Count);         Assert.IsTrue(peek_checkPQ(pq));       }     }   } } */