views:

514

answers:

5

I need to implement a priority queue where the priority of an item in the queue can change and the queue adjusts itself so that items are always removed in the correct order. I have some ideas of how I could implement this but I'm sure this is quite a common data structure so I'm hoping I can use an implementation by someone smarter than me as a base.

Can anyone tell me the name of this type of priority queue so I know what to search for or, even better, point me to an implementation?

A: 

Google has a number of answers for you, including an implementation of one in Java.

However, this sounds like something that would be a homework problem, so if it is, I'd suggest trying to work through the ideas yourself first, then potentially referencing someone else's implementation if you get stuck somewhere and need a pointer in the right direction. That way, you're less likely to be "biased" towards the precise coding method used by the other programmer and more likely to understand why each piece of code is included and how it works. Sometimes it can be a little too tempting to do the paraphrasing equivalent of "copy and paste".

Amber
Thanks Dav but this is a standard priority queue. If I add an item to the queue and it's priority is changed (outside of the queue), the order of the queue might be incorrect. In other words, a standard priority queue only sorts items when they are added to teh queue and not later. I need to implement a queue that updates as the priority of its items updates.P.S. It's not a homework problem, I need to implement this as part of some simulation software. I have some ideas of how I can implement it but want to see if there is a better way of doing it.
sean
Ah. Okay. In that case, I'd suggest looking for example implementations of Dijkstra's Algorithm, which (if implemented in its most efficient form) requires a reorderable priority queue, and thus should probably have what you're looking for.
Amber
A: 

A standard binary heap supports 5 operations (the example below assume a max heap):

* find-max: return the maximum node of the heap
* delete-max: removing the root node of the heap
* increase-key: updating a key within the heap
* insert: adding a new key to the heap
* merge: joining two heaps to form a valid new heap containing all the elements of both.

As you can see, in a max heap, you can increase an arbitrary key. In a min heap you can decrease an arbitrary key. You can't change keys both ways unfortunately, but will this do? If you need to change keys both ways then you might want to think about using a a min-max-heap.

Martin
A: 

I would suggest first trying the head-in approach, to update a priority:

  • delete the item from the queue
  • re-insert it with the new priority

In C++, this could be done using a std::multi_map, the important thing is that the object must remember where it is stored in the structure to be able to delete itself efficiently. For re-insert, it's difficult since you cannot presume you know anything about the priorities.

class Item;

typedef std::multi_map<int, Item*> priority_queue;

class Item
{
public:
  void add(priority_queue& queue);
  void remove();

  int getPriority() const;
  void setPriority(int priority);

  std::string& accessData();
  const std::string& getData() const;

private:
  int mPriority;
  std::string mData;

  priority_queue* mQueue;
  priority_queue::iterator mIterator;
};

void Item::add(priority_queue& queue)
{
  mQueue = &queue;
  mIterator = queue.insert(std::make_pair(mPriority,this));
}

void Item::remove()
{
  mQueue.erase(mIterator);
  mQueue = 0;
  mIterator = priority_queue::iterator();
}

void Item::setPriority(int priority)
{
  mPriority = priority;
  if (mQueue)
  {
    priority_queue& queue = *mQueue;
    this->remove();
    this->add(queue);
  }
}
Matthieu M.
Thanks Matthieu, I thought about using that approach but due to the frequency of update it wasn't efficient enough for my needs. I ended up using an implementation that included a dictionary mapping items to their indexes in the queue, then having a method on the queue, UpdatePosition(Item item), that looks up the items index and then bubbled it to its new position. The queue then has an event that the items register against so that they notify the queue when their priorities change. That seems to work well.
sean
A: 

Hi, I am looking for just exactly the same thing!

And here is some of my idea:

  1. Since a priority of an item keeps changing, it's meaningless to sort the queue before retrieving an item.
  2. So, we should forget using a priority queue. And "partially" sort the container while retrieving an item.

And choose from the following STL sort algorithms: a. partition b. stable_partition c. nth_element d. partial_sort e. partial_sort_copy f. sort g. stable_sort

partition, stable_partition and nth_element are linear-time sort algorithms, which should be our 1st choices.

BUT, it seems that there is no those algorithms provided in the official Java library. As a result, I will suggest you to use java.util.Collections.max/min to do what you want.

Henry
+1  A: 

Priority queues such as this are typically implemented using a binary heap data structure as someone else suggested, which usually is represented using an array but could also use a binary tree. It actually is not hard to increase or decrease the priority of an element in the heap. If you know you are changing the priority of many elements before the next element is popped from the queue you can temporarily turn off dynamic reordering, insert all of the elements at the end of the heap, and then reorder the entire heap (at a cost of O(n)) just before the element needs to be popped. The important thing about heaps is that it only costs O(n) to put an array into heap order but O(n log n) to sort it.

I have used this approach successfully in a large project with dynamic priorities.

Here is my implementation of a parameterized priority queue implementation in the Curl programming language.

Christopher Barber