In the study of data structures, linear data structures such as arrays, linked lists, stacks, and queues organize data elements in a sequential manner. For example, a queue follows the First-In-First-Out (FIFO) principle, where elements are processed in the exact order they arrive.
However, many real-world scenarios require processing elements not just by arrival time but by their importance or priority. This is where priority queues come into play. A priority queue is a special type of queue where each element is associated with a priority, and elements with higher priority are processed before those with lower priority, regardless of their arrival order.
Understanding priority queues is essential for solving problems that involve scheduling, resource management, and optimization, especially in competitive exams and real-world applications.
A priority queue is an abstract data type similar to a regular queue but with an added feature: each element has a priority. When removing (dequeueing) an element, the one with the highest priority is always chosen first.
Unlike a regular queue where the order is strictly FIFO, a priority queue orders elements based on their priority values.
For example, consider a hospital emergency room:
In the diagram above, elements labeled A to E have different priorities (numbers in parentheses). When dequeuing, the element with the highest priority (C with 8) is removed first, followed by E (7), then B (5), and so on, regardless of their original order in the queue.
Priority queues can be implemented using several data structures, each with its own advantages and disadvantages. The most common methods are:
| Implementation | Insertion Complexity | Deletion (Extract Max/Min) Complexity | Ease of Implementation | Notes |
|---|---|---|---|---|
| Unsorted Array | O(1) | O(n) (search for max/min) | Easy | Fast insertion, slow deletion |
| Sorted Array | O(n) (insert at correct position) | O(1) | Moderate | Fast deletion, slow insertion |
| Sorted Linked List | O(n) (traverse to insert) | O(1) | Moderate | Dynamic size, no shifting needed |
| Heap (Binary Heap) | O(log n) | O(log n) | Moderate to Complex | Balanced performance, widely used |
The heap-based implementation is the most efficient for large datasets, offering logarithmic time for both insertion and deletion. Arrays and linked lists can be simpler but may suffer from slower operations depending on whether they are sorted or unsorted.
The main operations supported by priority queues are:
Below is a flowchart illustrating the insertion and deletion process in a heap-based priority queue:
graph TD A[Start] --> B{Operation?} B -->|Insert| C[Add element at end] C --> D[Heapify-up to maintain heap property] D --> E[Insertion complete] B -->|Delete| F[Remove root element] F --> G[Replace root with last element] G --> H[Heapify-down to maintain heap property] H --> I[Deletion complete]In a max-heap (a common type of heap), the root node always contains the element with the highest priority. When inserting, the new element is added at the end and then "heapified up" to restore the max-heap property. When deleting, the root is removed, replaced by the last element, and then "heapified down".
Step 1: Insert 15.
Heap: [15]
Step 2: Insert 10.
Heap before heapify-up: [15, 10]
Since 10 < 15, no change.
Heap after heapify-up: [15, 10]
Step 3: Insert 30.
Heap before heapify-up: [15, 10, 30]
Compare 30 with parent 15; 30 > 15, so swap.
Heap after heapify-up: [30, 10, 15]
Step 4: Insert 40.
Heap before heapify-up: [30, 10, 15, 40]
Compare 40 with parent 10; 40 > 10, swap.
Heap now: [30, 40, 15, 10]
Compare 40 with new parent 30; 40 > 30, swap.
Heap after heapify-up: [40, 30, 15, 10]
Step 5: Insert 20.
Heap before heapify-up: [40, 30, 15, 10, 20]
Compare 20 with parent 30; 20 < 30, no swap.
Heap after heapify-up: [40, 30, 15, 10, 20]
Answer: Final max-heap array representation is [40, 30, 15, 10, 20].
Step 1: Remove the root element 50.
Step 2: Replace root with last element 20.
Heap now: [20, 30, 40, 10]
Step 3: Heapify-down from root:
Heap now: [40, 30, 20, 10]
Step 4: Continue heapify-down at index of 20:
Answer: Heap after extraction: [40, 30, 20, 10]
Step 1: Insert 25.
List: 25
Step 2: Insert 15.
Insert 15 in sorted order (descending): 25 -> 15
Step 3: Insert 30.
30 > 25, so insert at head: 30 -> 25 -> 15
Step 4: Insert 10.
Insert at end: 30 -> 25 -> 15 -> 10
Step 5: Delete highest priority element (head): remove 30.
List after deletion: 25 -> 15 -> 10
Answer: Final linked list after operations is 25 -> 15 -> 10.
Step 1: Insert processes into a max-priority queue based on priority values.
Insert P1(3): Queue: [P1]
Insert P2(1): Queue: [P1, P2]
Insert P3(4): Queue after heapify: [P3, P2, P1]
Insert P4(2): Queue after heapify: [P3, P4, P1, P2]
Step 2: Process execution order is determined by extracting max priority:
Answer: The CPU executes processes in order: P3 -> P1 -> P4 -> P2.
Step 1: Insert vertices with their current distances into a min-priority queue.
Queue: [(A,0), (B,4), (C,2), (D,∞)]
Step 2: Extract the vertex with minimum distance.
Extracted: A(0)
Step 3: Update distances of neighbors and reinsert or update their priorities in the queue as needed.
Answer: The priority queue efficiently selects the next vertex with the smallest tentative distance, which is crucial for Dijkstra's algorithm's performance.
When to use: When you need efficient access to either maximum or minimum priority elements.
When to use: During heap implementation or debugging.
When to use: When ease of implementation is more important than performance.
When to use: Preparing for competitive exams or coding interviews.
When to use: When solving graph or encoding problems requiring efficient priority management.
Progress tracking is paywalled — subscribe to mark subtopics as understood and save your streak.
Go to practice →