Priority queue

From Wikipedia, the free encyclopedia

Jump to: navigation, search

A priority queue is an abstract data type in computer programming that supports the following three operations:

  • InsertWithPriority: add an element to the queue with an associated priority
  • GetNext: remove the element from the queue that has the highest priority, and return it (also known as "PopElement(Off)", or "GetMinimum")
  • PeekAtNext (optional): look at the element with highest priority without removing it

For an analogy, see the Implementation section below.

Contents

[edit] Similarity to Queues

One can imagine a priority queue as a modified queue, but when one would get the next element off the queue, the highest-priority one is retrieved first.

A queue is a special case of a priority queue where an element's priority is the time (or negative of the time) that element was inserted.

[edit] Implementation

[edit] Simple implementations

There are a variety of simple, usually-inefficient ways to implement a priority queue. They provide an analogy to help one understand what a priority queue is:

  • Sorted list implementation: Like a checkout line at the supermarket, but where important people get to "cut" in front of less important people. (O(n) insertion time, O(1) get-next time)
  • Unsorted list implementation: Keep a list of elements as the queue. To add an element, append it to the end. To get the next element, search through all elements for the one with the highest priority. (O(1) insertion time, O(n) get-next due to search)

These implementations are usually inefficient, though can be good depending on the workload (for example, if one does very few GetNext operations, the unsorted list approach may work well). In practice, priority queues blend these two approaches, so any operation takes roughly O(log(n)) time or less.

[edit] Usual implementation

To get better performance, priority queues typically use a heap (such as a Fibonacci heap) as their backbone, giving O(1) performance for inserts, and O(log n) for removals. Alternatively, if a self-balancing binary search tree is used, all three operations take O(log n) time; this is a popular solution where one already has access to these data structures, such as through third-party or standard libraries.

[edit] Effect of different data structures

The designer of the priority queue should take into account what sort of access pattern the priority queue will be subject to, and what computational resources are most important to the designer. The designer can then use various specialized types of heaps:

There are a number of specialized heap data structures that either supply additional operations or outperform the above approaches. The binary heap uses O(log n) time for both operations, but allows peeking at the element of highest priority without removing it in constant time. Binomial heaps add several more operations, but require O(log n) time for peeking. Fibonacci heaps can insert elements, peek at the maximum priority element, and increase an element's priority in amortized constant time (deletions are still O(log n)).

While relying on a heap is a common way to implement priority queues, for integer data faster implementations exist (this can even apply to datatypes that have finite range, such as floats):

  • When the set of keys is {1, 2, ..., C}, a data structure by van Emde Boas supports the minimum, maximum, insert, delete, search, extract-min, extract-max, predecessor and successor operations in O(loglogC) time, but has a space cost for small queues of about O(2m/2), where m is the number of bits in the priority value.[1]
  • An algorithm by Fredman and Willard implements the minimum operation in O(1) time and insert and extract-min operations in O(\sqrt{\log n}) time.[2]

For applications that do many "peek" operations for every "extract-min" operation, the time complexity for peek can be reduced to O(1) in all tree and heap implementations by caching the highest priority element after every insertion and removal. (For insertion this adds at most constant cost, since the newly inserted element need only be compared to the previously cached minimum element. For deletion, this at most adds an additional "peek" cost, which is nearly always cheaper than the deletion cost, so overall time complexity is not affected by this change).

[edit] Container libraries

The Standard Template Library (STL), and the C++ 1998 standard, specifies priority_queue as one of the STL container adaptor class templates. Unlike actual STL containers, it does not allow iteration of its elements (it strictly adheres to its abstract data type definition). STL also has utility functions for manipulating another random-access container as a binary max-heap, as does Python's heapq module, which implements a binary min-heap.

The Boost C++ Libraries (current version 1.38), implements several algorithms for efficient priority queues.

Java's library contains a PriorityQueue class.

[edit] Applications

[edit] Bandwidth management

Priority queuing can be used to manage limited resources such as bandwidth on a transmission line from a network router. In the event of outgoing traffic queuing due to insufficient bandwidth, all other queues can be halted to send the traffic from the highest priority queue upon arrival. This ensures that the prioritized traffic (such as real-time traffic, e.g. an RTP stream of a VoIP connection) is forwarded with the least delay and the least likelihood of being rejected due to a queue reaching its maximum capacity. All other traffic can be handled when the highest priority queue is empty. Another approach used is to send disproportionately more traffic from higher priority queues.

Usually a limitation (policer) is set to limit the bandwidth that traffic from the highest priority queue can take, in order to prevent high priority packets from choking off all other traffic. This limit is usually never reached due to high lever control instances such as the Cisco Callmanager, which can be programmed to inhibit calls which would exceed the programmed bandwidth limit.

[edit] Discrete event simulation

Another use of a priority queue is to manage the events in a discrete event simulation. The events are added to the queue with their simulation time used as the priority. The execution of the simulation proceeds by repeatedly pulling the top of the queue and executing the event thereon.

See also: Scheduling (computing), queueing theory

[edit] A* and SMA* search algorithms

The A* search algorithm finds the shortest path between two vertices of a weighted graph, trying out the most promising routes first. The priority queue (also known as the fringe) is used to keep track of unexplored routes; the one for which a lower bound on the total path length is smallest is given highest priority. If memory limitations make A* impractical, the SMA* algorithm can be used instead, with a double-ended priority queue to allow removal of low-priority items.

[edit] ROAM triangulation algorithm

The Real-time Optimally Adapting Meshes (ROAM) algorithm computes a dynamically changing triangulation of a terrain. It works by splitting triangles where more detail is needed and merging them where less detail is needed. The algorithm assigns each triangle in the terrain a priority, usually related to the error decrease if that triangle would be split. The algorithm uses two priority queues, one for triangles that can be split and another for triangles that can be merged. In each step the triangle from the split queue with the highest priority is split, or the triangle from the merge queue with the lowest priority is merged with its neighbours.

[edit] Relationship to sorting algorithms

The semantics of priority queues naturally suggest a sorting method: insert all the elements to be sorted into a priority queue, and sequentially remove them; they will come out in sorted order. This is actually the procedure used by several sorting algorithms, once the layer of abstraction provided by the priority queue is removed. This sorting method is equivalent to the following sorting algorithms:

  • Heapsort if the priority queue is implemented with a heap.
  • Selection sort if the priority queue is implemented with an unordered array.
  • Insertion sort if the priority queue is implemented with an ordered array.

A sorting algorithm can also be used to implement a priority queue.

[edit] External links

[edit] References

  1. ^ P. van Emde Boas. Preserving order in a forest in less than logarithmic time. In Proceedings of the 16th Annual Symposium on Foundations of Computer Science, pages 75-84. IEEE Computer Society, 1975.
  2. ^ Michael L. Fredman and Dan E. Willard. Surpassing the information theoretic bound with fusion trees. Journal of Computer and System Sciences, 48(3):533-551, 1994
Personal tools