Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change the priority in a custom priority queue

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();
    }
}
  1. How to manage the transition from FIFO mode to priority mode when there are still elements in the default queue? I could copy them in the priority queues based on the item priority... Other better solutions?
  2. How to manage the transition from priority mode to FIFO mode? In this case, I would have several priority queues, which may contain elements, but no longer have to manage them according to priority and not even know the original order of arrival...
  3. How can I manage the capacity of the different queues?
  4. What about the performances of the above two solutions? Which does use more memory?
like image 388
enzom83 Avatar asked Feb 10 '12 18:02

enzom83


Video Answer


2 Answers

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).

like image 57
Branko Dimitrijevic Avatar answered Oct 14 '22 15:10

Branko Dimitrijevic


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 prioritykey to return to the regular behavior.

like image 34
Avi Cohen Avatar answered Oct 14 '22 15:10

Avi Cohen