In computer science, a priority queue is an abstract data type similar to a regular queue where each element has an associated priority determining its order of service. Priority queue serves highest priority items first. Priority values have to be instances of an ordered data type, and higher priority can be given either to the lesser or to the greater values with respect to the given order relation. For example, in the Java standard library, the PriorityQueue class considers the lowest element with respect to their order as having the highest priority.
While priority queues are often implemented using heaps, they are conceptually distinct. A priority queue can be implemented with a heap or with other methods; just as a list can be implemented with a linked list or with an array.
Operations
A priority queue has the following operations:
Max-priority queue insert(S, element, priority): add an element to set S with an associated priority.
maximum(S): return the element with highest priority. This is also known as "find_max".
extract_max(S): remove the element from set S with highest priority, and return it. This is also known as "delete", or "extract".
increase_key(S, element, k): increase the associated priority with an element to the new value k.
Min-priority queue insert(S, element, priority): add an element to set S with an associated priority.
minimum(S): return the element with lowest priority. This is also known as "find_min".
extract_min(S): remove the element from set S with lowest priority, and return it. This is also known as "delete", or "extract".
decrease_key(S, element, k): decrease the associated priority with an element to the new value k.
Stacks and queues can be implemented as particular kinds of priority queues, with the priority determined by the order in which the elements are inserted. In a stack, the priority of each inserted element is monotonically increasing; thus, the last element inserted is always the first retrieved. In a queue, the priority of each inserted element is monotonically decreasing; thus, the first element inserted is always the first retrieved.
In some implementations, if two elements have the same priority, they are served in the same order in which they were enqueued. In other implementations, the order of elements with the same priority is undefined.
Implementation
Naive implementations
One can create a simple, but inefficient priority queue in a number of ways. These naive implementations can demonstrate the expected behaviour of a priority queue in a simpler manner.
insert elements into an unsorted array; find and extract element with highest priority Performance: "insert" performs in constant time, where "extract_max" performs in linear time.
insert(element, priority): node.element ← element node.priority ← priority list.append(node)
extract_max(): highest ← 0 foreach node in list: if highest.priority < node.priority: highest ← node list.remove(highest) return highest.element
insert elements into a sorted array; extract first element Performance: "insert" performs in linear time, where "extract_max" performs in constant time.
insert(element, priority): node.element ← element node.priority ← priority for i in [0...N]: element ← list.get_at_index(i) if element.priority < node.priority: list.insert_at_index(node, i + 1) return
extract_max(): highest ← list.get_at_index(0) list.remove(highest) return highest.element
Usual implementation
To improve performance, priority queues are typically based on a heap, giving performance for inserts and removals, and to build the heap initially from a set of elements. Variants of the basic heap data structure such as pairing heaps or Fibonacci heaps can provide better bounds for some operations. Third edition, p. 518.
Alternatively, when a self-balancing binary search tree is used, insertion and removal also take time, although building trees from existing sequences of elements takes time; this is typical where one might already have access to these data structures, such as with third-party or standard libraries. From a space-complexity standpoint, using self-balancing binary search tree with linked list takes more storage, since it requires storing extra references to other nodes.
From a computational-complexity standpoint, priority queues are congruent to sorting algorithms. The section on the equivalence of priority queues and sorting algorithms, below, describes how efficient sorting algorithms can create efficient priority queues.
Specialized heaps There are several specialized heap data structures that either supply additional operations or outperform heap-based implementations for specific types of keys, specifically integer keys. Suppose the set of possible keys is .
When only insert, find-min and extract-min are needed and in case of integer priorities, a bucket queue can be constructed as an array of linked lists plus a pointer , initially . Inserting an item with key appends the item to the 'th list, and updates , both in constant time. extract-min deletes and returns one item from the list with index , then increments if needed until it again points to a non-empty list; this takes time in the worst case. These queues are useful for sorting the vertices of a graph by their degree. A van Emde Boas tree supports the minimum, maximum, insert, delete, search, extract-min, extract-max, predecessor and successor] operations in time, but has a space cost for small queues of about , where is the number of bits in the priority value.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. The space can be reduced significantly with hashing. The Fusion tree by Fredman and Willard implements the minimum operation in time and insert and extract-min operations in time. However it is stated by the author that, "Our algorithms have theoretical interest only; The constant factors involved in the execution times preclude practicality."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
For applications that do many "peek" operations for every "extract-min" operation, the time complexity for peek actions can be reduced to in all tree and heap implementations by caching the highest priority element after every insertion and removal. For insertion, this adds at most a constant cost, since the newly inserted element is compared only to the previously cached minimum element. For deletion, this at most adds an additional "peek" cost, which is typically cheaper than the deletion cost, so overall time complexity is not significantly impacted.
Monotone priority queues are specialized queues that are optimized for the case where no item is ever inserted that has a lower priority (in the case of min-heap) than any item previously extracted. This restriction is met by several practical applications of priority queues.
Summary of running times
Equivalence of priority queues and sorting algorithms
Using a priority queue to sort
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:
Name Priority queue implementation Best Average Worst Heapsort Heap Smoothsort Leonardo heap Selection sort Unordered array Insertion sort Ordered array Tree sort Self-balancing binary search tree
Using a sorting algorithm to make a priority queue
A sorting algorithm can also be used to implement a priority queue. Specifically, Thorup says:
We present a general deterministic linear space reduction from priority queues to sorting implying that if we can sort up to keys in time per key, then there is a priority queue supporting delete and insert in time and find-min in constant time.
That is, if there is a sorting algorithm which can sort in time per key, where is some function of and word size, then one can use the given procedure to create a priority queue where pulling the highest-priority element is time, and inserting new elements (and deleting elements) is time. For example, if one has an sort algorithm, one can create a priority queue with pulling and insertion.
Libraries
A priority queue is often considered to be a "container data structure".
The Standard Template Library (STL), and the C++ 1998 standard, specifies as one of the STL container adaptor class templates. However, it does not specify how two elements with same priority should be served, and indeed, common implementations will not return them according to their order in the queue. It implements a max-priority-queue, and has three parameters: a comparison object for sorting such as a function object (defaults to if unspecified), the underlying container for storing the data structures (defaults to ), and two iterators to the beginning and end of a sequence. 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. The Boost libraries also have an implementation in the library heap.
Python's module implements a binary min-heap on top of a list.
Java's library contains a (java.util.PriorityQueue) class, which implements a min-priority-queue as a binary heap.
.NET's library contains a System.Collections.Generic.PriorityQueue class, which implements an array-backed, quaternary min-heap.
Scala's library contains a class, which implements a max-priority-queue.
Go's library contains a module, which implements a min-heap on top of any compatible data structure.
Rust's standard library contains a struct, which implements a priority queue with a binary heap.
The Standard PHP Library extension contains the class .
Apple's Core Foundation framework contains a structure, which implements a min-heap.
Applications
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.
Many modern protocols for local area networks also include the concept of priority queues at the media access control (MAC) sub-layer to ensure that high-priority applications (such as VoIP or IPTV) experience lower latency than other applications which can be served with best-effort service. Examples include IEEE 802.11e (an amendment to IEEE 802.11 which provides quality of service) and ITU-T G.hn (a standard for high-speed local area network using existing home wiring (power lines, phone lines and coaxial cables).