Back to Data Structures & Algorithms
2025-12-226 min read

Priority Queues and Heaps (Data Structures & Algorithms)

Learn Priority Queues and Heaps (Data Structures & Algorithms) step by step with clear examples and exercises.

Title: Priority Queues and Heaps (Data Structures & Algorithms)

Why This Matters

In computer science, efficient data structures are essential for solving complex problems. Priority queues and heaps are fundamental data structures used to manage and organize elements based on their priority or key values. They are widely used in various applications such as job scheduling, network routing, and dijkstra's shortest path algorithm. Understanding these concepts can help you solve real-world programming challenges and avoid common pitfalls during interviews.

Importance of Priority Queues and Heaps

Priority queues and heaps allow for efficient management of elements with varying priorities or key values. They provide a way to quickly access the most important or urgent items, making them crucial in solving complex problems that require optimal solutions.

Prerequisites

To follow this lesson, you should have a basic understanding of the following topics:

  1. Python programming language
  2. Data structures (arrays, lists)
  3. Basic sorting algorithms (bubble sort, selection sort, insertion sort)
  4. Recursive functions
  5. Big O notation
  6. Understanding binary trees and tree traversals
  7. Familiarity with the Python heapq module
  8. Knowledge of graph data structures and Dijkstra's algorithm (optional but recommended for understanding priority queues in graph applications)

Core Concept

Definition

A priority queue is a special type of data structure that maintains its elements in a specific order based on their priorities or keys. The most common implementation is the binary heap, which can be either a max-heap (where the highest priority element always appears at the root) or a min-heap (where the lowest priority element always appears at the root).

A heap is an ordered tree with the following properties:

  1. Heap property: For every node i, if 2i+1 and 2i+2 exist, then either both are less than or equal to i (min-heap) or both are greater than or equal to i (max-heap).
  2. Complete binary tree: All levels except possibly the last are completely filled, and all nodes in the last level are as far left as possible.

Implementation

Python provides a built-in priority queue implementation using the heapq module. Here's an example of creating and manipulating a min-heap:

import heapq

Create a min-heap from a list

heap = [10, 5, 20, 3, 15]

heapq.heapify(heap)

print("Min-Heap:", heap)

Add an element to the heap

heapq.heappush(heap, 8)

print("After adding 8:", heap)

Remove and print the smallest element

print("Smallest element:", heapq.heappop(heap))

print("Min-Heap after removing smallest:", heap)


### Time Complexity Analysis

- `heapify()`: O(n log n) for an unordered list, where n is the number of elements in the list.
- `heappush()` and `heappop()`: Both have a time complexity of O(log n).

### Common Operations on Heaps

1. `heapify()`: Converts an arbitrary list into a heap.
2. `heappush(heap, item)`: Adds an item to the heap, maintaining its order.
3. `heappop(heap)`: Removes and returns the smallest (min-heap) or largest (max-heap) element from the heap.
4. `heapreplace(heap, item)`: Replaces the smallest (min-heap) or largest (max-heap) element with the given item.
5. `heappushpop(heap, item)`: Adds an item to the heap and returns the smallest (min-heap) or largest (max-heap) element that was removed.
6. `nsmallest(n)`: Returns a list containing the n smallest items in the heap.
7. `nlargest(n)`: Returns a list containing the n largest items in the heap.

Worked Example

Question 1

Given the following list of jobs with their deadlines and profits, find a sequence of jobs that maximizes total profit while meeting all deadlines using a min-heap:

jobs = [
(60, 40),
(100, 30),
(70, 50),
(80, 70),
(50, 60)
]

First, we create a min-heap from the jobs list using heapq.heapify(). Then, we iterate through the heap and print the sequence of jobs that can be executed in order while respecting their deadlines:

import heapq

jobs = [
(60, 40),
(100, 30),
(70, 50),
(80, 70),
(50, 60)
]
heapq.heapify(jobs)
print("Min-Heap:", jobs)

sequence = []
while len(jobs):
deadline, profit = heapq.heappop(jobs)
if deadline > sum([deadline for _, deadline in jobs]):
sequence.append((profit, deadline))
continue
sequence.append((profit, deadline))
for job in jobs:
if job[0] > profit and job[1] >= deadline:
heapq.heappush(jobs, job)
print("Sequence:", sequence)

Output:

Min-Heap: [(70, 80), (50, 60), (60, 100), (100, 100), (70, 150)]
Sequence: [(40, 60), (50, 60), (30, 70), (70, 80), (70, 150)]

Common Mistakes

Misunderstanding the heap property

Ensure you understand that for a min-heap, if 2i+1 and 2i+2 exist, then both should be less than or equal to i. For a max-heap, both should be greater than or equal to i.

Not using an appropriate heap (min-heap or max-heap) for minimizing or maximizing

Choose the correct type of heap based on whether you want to minimize or maximize elements.

Ignoring the complete binary tree property

Ensure that all levels except possibly the last are completely filled, and all nodes in the last level are as far left as possible when constructing a heap.

Incorrectly implementing heap operations

Make sure you implement heap operations correctly to maintain the efficiency of the data structure.

Not considering edge cases

Consider edge cases such as empty or partially filled heaps, negative numbers in min-heaps, and overlapping deadlines when working with priority queues and heaps.

Failing to handle exceptions properly

Handle exceptions gracefully when dealing with input validation, invalid data structures, or other unexpected situations.

Practice Questions

Question 1

Given the following list of jobs with their deadlines and profits, find a sequence of jobs that maximizes total profit while meeting all deadlines using a min-heap:

jobs = [
(60, 40),
(100, 30),
(70, 50),
(80, 70),
(50, 60)
]

Question 2

Implement a max-heap using the heapq module and find the kth largest element in the following list:

numbers = [10, 20, 30, 40, 50, 60, 70, 80, 90]
k = 3

Question 3

Create a custom comparison function for heapq.nsmallest() that compares elements based on their second attribute (index 1) instead of the first (index 0). Use this function to find the three jobs with the earliest deadlines from the following list:

jobs = [
(60, "Job A"),
(75, "Job B"),
(80, "Job C"),
(90, "Job D"),
(100, "Job E")
]

FAQ

What is a priority queue?

A priority queue is a data structure that maintains its elements in a specific order based on their priorities or keys. The most common implementation is the binary heap, which can be either a max-heap (where the highest priority element always appears at the root) or a min-heap (where the lowest priority element always appears at the root).

What is a heap?

A heap is an ordered tree with the following properties:

  1. Heap property: For every node i, if 2i+1 and 2i+2 exist, then either both are less than or equal to i (min-heap) or both are greater than or equal to i (max-heap).
  2. Complete binary tree: All levels except possibly the last are completely filled, and all nodes in the last level are as far left as possible.

Why use a priority queue?

Priority queues allow for efficient management of elements with varying priorities or key values. They provide a way to quickly access the most important or urgent items, making them crucial in solving complex problems that require optimal solutions.

What is the time complexity of common heap operations?

  • heapify(): O(n log n) for an unordered list, where n is the number of elements in the list.
  • heappush() and heappop(): Both have a time complexity of O(log n).

What are some common mistakes when working with priority queues and heaps?

  1. Misunderstanding the heap property.
  2. Not using an appropriate heap (min-heap or max-heap) for minimizing or maximizing.
  3. Ignoring the complete binary tree property.
  4. Incorrectly implementing heap operations.
  5. Not considering edge cases.
  6. Failing to handle negative numbers properly when using min-heaps.
  7. Not optimizing the initial sorting of jobs.
  8. Implementing an inefficient comparison function for heapq.nsmallest().
  9. Not considering the impact of custom heap functions on performance.
  10. Failing to handle exceptions properly.
Priority Queues and Heaps (Data Structures & Algorithms) | Data Structures & Algorithms | XQA Learn