I followed the directions given in this question (the answer by Jason) in order to write my PriorityQueue<T>
using a SortedList
. I understand that the count
field within this class is used to ensure unique priorities and to preserve the enqueue order among the same priority.
However, when count
reaches its maximum value and I sum 1 to it, the latter will starts again from 0, so the priority of the subsequent items would be higher than the priority of the previous items. Using this approach I could need for a way to "securely" reset the counter count
... In fact, suppose to have the following queue state (in the format priority | count | item):
0 | 123 | A
0 | 345 | B
1 | 234 | C
2 | 200 | D
Now suppose the counter limit has reached, so I have to reset it to 0: as a consequence, the next inserted item will have counter 0: for example, if I insert an element with priority equal to 1, it will be wrongly inserted before 1 | 234 | D
0 | 123 | A
0 | 345 | B
1 | 000 | new element
1 | 234 | C
2 | 200 | D
The problem of the priority can be solved by implementing an heap: I created an Heap
class, then I used Heap<KeyValuePair<TPriority, TElement>
and a custom PriorityComparer
in order to sort elements by TPriority
.
Given TPriority as an int
and TElement as a string
, the PriorityComparer
is as follows:
public class MyComparer : IComparer<KeyValuePair<int, string>>
{
public int Compare(KeyValuePair<int, string> x, KeyValuePair<int, string> y)
{
return x.Key.CompareTo(y.Key);
}
}
...
int capacity = 10;
Heap<KeyValuePair<int, string>> queue;
queue = new Heap<KeyValuePair<int, string>>(capacity, new PriorityComparer());
...
UPDATE
In this way (using the PriorityComparer
), I have succeeded to implement a priority queue.
Now I'd like to add support to modify its behavior at runtime, ie switch from FIFO to priority sorting and vice-versa. Since my implementation of priority queue has an IComparer
field, I think it is sufficient to add a Comparer
property to edit this field, like as follows:
public IComparer
{
set
{
this._comparer = value;
}
}
In the meantime I thought I'd take a different approach: instead of using a binary heap to manage priorities, I could wrap different queues (each queue refers to a given priority) as follows.
public class PriorityQueue<T, int>
{
private Queue<T> _defaultQueue;
private bool _priority;
private SortedList<int, Queue<T>> _priorityQueues;
public PriorityQueue(int capacity)
{
this._defaultQueue = new Queue<T>(capacity);
this._priority = false;
this._priorityQueues = new SortedList<int, Queue<T>>(0);
}
public void PriorityEnable()
{
this._priority = true;
}
public void PriorityDisable()
{
this._priority = false;
}
public void Enqueue(T item)
{
if (this._priority)
{
// enqueue to one of the queues
// with associated priority
// ...
}
else this._defaultQueue.Enqueue(item);
}
public T Dequeue()
{
if (this._priority)
{
// dequeue from one of the queues
// with associated priority and
// return
// ...
}
return this._defaultQueue.Dequeue();
}
}
You could "cheat" and use BigInteger so you never "run out of numbers". This of course leads to gradual deterioration of performance over time, but probably not significant enough to matter.
Combine that with a heap-based priority queue and you are set!
Don't try to "switch from FIFO to priority sorting and vice-versa" - simply put elements in both data structures appropriate for the task (Queue and priority queue).
Using both Queue
and Priority Queue
is what I would do.
But if you must...
Instead of one key use 2 keys for an element.
The first key priority
will be the priority.
The second key time
will be a counter that will be like a timestamp.
For the regular behavior use the priority
key.
When the heap is full, HEAPIFY
it by the time
key.
Then remove n
needed elements.
Now HEAPIFY
it again with the priority
key to return to the regular behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With