AiTechWorlds
AiTechWorlds
University learning companion
Data Structures · Deques and Priority Queues
Use this course-level map to place “Deques and Priority Queues” in the larger system. It complements—not replaces—a topic-specific worked diagram.
Track enqueue and dequeue as elements move through a first-in-first-out queue.
Image source and attribution · Pat Hawks · CC BY-SA 4.0 · Wikimedia Commons · Unmodified · Licence details
A deque (double ended queue) allows insertion and removal from both ends, while a priority queue always serves the highest priority element next regardless of arrival order.
Imagine a hospital emergency room at 2 AM. The waiting room has a queue patients arrive and take a number. But then an ambulance rolls in with someone in critical condition. Should that patient wait behind the person with a sprained ankle who arrived twenty minutes earlier?
Of course not. The hospital uses priority. Critical patients jump to the front regardless of when they arrived. Someone with a minor issue waits even if they got there first. This is the real world, and sometimes importance matters more than order.
This is exactly what a priority queue models. And to understand it fully, we first look at its cousin: the deque.
A regular queue allows adding to the back and removing from the front. A deque (pronounced "deck," short for double ended queue) is more flexible: you can add or remove from either end.
Think of a train car passengers can board or exit from both the front door and the rear door.
collections.dequePython's built in deque supports all four directional operations in O(1):
from collections import deque
d = deque()
# Adding elements
d.append("C") # Add to the RIGHT (back) → deque(['C'])
d.append("D") # Add to the RIGHT → deque(['C', 'D'])
d.appendleft("B") # Add to the LEFT (front) → deque(['B', 'C', 'D'])
d.appendleft("A") # Add to the LEFT → deque(['A', 'B', 'C', 'D'])
print("Deque:", d) # deque(['A', 'B', 'C', 'D'])
# Removing elements
print(d.pop()) # Remove from RIGHT → 'D' deque(['A', 'B', 'C'])
print(d.popleft()) # Remove from LEFT → 'A' deque(['B', 'C'])
# Peeking without removing
print(d[0]) # Front element → 'B'
print(d[-1]) # Back element → 'C'
# Useful extras
d.rotate(1) # Rotate right — last element moves to front
print(d) # deque(['C', 'B'])
d.rotate(-1) # Rotate left — first element moves to back
print(d) # deque(['B', 'C'])Output:
Deque: deque(['A', 'B', 'C', 'D'])
D
A
B
C
deque(['C', 'B'])
deque(['B', 'C'])deque Operations at a Glance| Operation | Description | Time Complexity |
|---|---|---|
append(x) | Add to the right (back) | O(1) |
appendleft(x) | Add to the left (front) | O(1) |
pop() | Remove from the right | O(1) |
popleft() | Remove from the left | O(1) |
d[0] / d[-1] | Peek at front or back | O(1) |
rotate(n) | Rotate n steps right (or left) | O(n) |
len(d) | Number of elements | O(1) |
Deques are perfect for sliding window problems, implementing both stacks and queues, and palindrome checking (compare from both ends simultaneously).
A priority queue is an abstract data structure where each element has an associated priority. The element with the highest priority is always removed first, regardless of insertion order.
Priority Queue: A collection where each element has a key (priority), and
dequeue()always returns the element with the minimum (or maximum) priority key.
This is not FIFO. It is not LIFO. It is priority ordered.
heapq ModuleThe most efficient implementation of a priority queue uses a binary heap a tree structure that keeps the smallest element at the top. Python's heapq module gives you a min heap directly on a regular list.
heapqimport heapq
tasks = []
# heappush(heap, item) — add item to heap while maintaining heap order
heapq.heappush(tasks, (3, "Low priority task"))
heapq.heappush(tasks, (1, "URGENT: Server down!"))
heapq.heappush(tasks, (2, "Medium priority"))
heapq.heappush(tasks, (1, "URGENT: Payment failed!"))
# heappop(heap) — always removes and returns the SMALLEST item
print("Processing tasks by priority:")
while tasks:
priority, task = heapq.heappop(tasks)
print(f" Priority {priority}: {task}")Output:
Processing tasks by priority:
Priority 1: URGENT: Payment failed!
Priority 1: URGENT: Server down!
Priority 2: Medium priority
Priority 3: Low priority taskThe two priority-1 tasks are processed before priority-2 and priority-3, regardless of the order they were added. Ties in priority are broken by the second element (string comparison).
import heapq
tasks = [(3, "Low"), (1, "High"), (2, "Medium")]
heapq.heapify(tasks) # Convert existing list into a valid heap
print("Next task:", tasks[0]) # Peek at the min without removing
# Output: Next task: (1, 'High')heapq is a min heap by default. To simulate a max heap, negate the priority values:
import heapq
max_heap = []
heapq.heappush(max_heap, (-5, "Very important"))
heapq.heappush(max_heap, (-1, "Not important"))
heapq.heappush(max_heap, (-3, "Somewhat important"))
while max_heap:
neg_priority, task = heapq.heappop(max_heap)
print(f"Priority {-neg_priority}: {task}")Output:
Priority 5: Very important
Priority 3: Somewhat important
Priority 1: Not importantqueue.PriorityQueueFor multi threaded programs where multiple threads add and remove tasks simultaneously, queue.PriorityQueue is the safe choice:
from queue import PriorityQueue
pq = PriorityQueue()
pq.put((2, "Normal task"))
pq.put((1, "High priority"))
pq.put((3, "Background task"))
while not pq.empty():
priority, task = pq.get()
print(f" [{priority}] {task}")Output:
[1] High priority
[2] Normal task
[3] Background taskqueue.PriorityQueue uses locks internally, making it safe for concurrent access. heapq does not it is single threaded only.
| Operation | Time Complexity | Notes |
|---|---|---|
heappush() | O(log n) | Insert + reheapify |
heappop() | O(log n) | Remove min + reheapify |
heapify() | O(n) | Build heap from existing list |
Peek (heap[0]) | O(1) | Minimum is always at index 0 |
Dijkstra's Algorithm Finding the shortest path in a weighted graph. The algorithm always processes the unvisited node with the smallest known distance. A priority queue makes this efficient.
Operating System Process Scheduling The OS assigns priorities to processes. Higher priority processes (like system tasks) get CPU time before lower priority ones (background downloads).
Event Driven Simulation Simulating events over time. Each event has a timestamp as its priority. The simulator always processes the earliest scheduled event next.
A Pathfinding* Used in game AI and GPS navigation. Nodes are explored in order of estimated total cost, managed by a priority queue.
Hospital Triage Systems Exactly the opening analogy. Critical conditions get priority over routine cases, regardless of arrival time.
| Feature | Queue (FIFO) | Deque | Priority Queue |
|---|---|---|---|
| Add to | Back only | Front or back | Any order |
| Remove from | Front only | Front or back | Always min/max first |
| Ordering rule | Arrival order | Depends on use | Priority key |
| Python tool | deque | deque | heapq / PriorityQueue |
| Insert time | O(1) | O(1) | O(log n) |
| Remove time | O(1) | O(1) | O(log n) |
When the order of processing must reflect importance rather than arrival time, a priority queue is the right tool. Use heapq for fast single threaded code, and queue.PriorityQueue when threads are involved. Deques are the flexible generalization of queues useful when you need access from both ends. Together, these structures cover a huge range of scheduling, search, and simulation problems.
University learning companion
Data Structures · Deques and Priority Queues
Complete the steps without looking at the answer first; record evidence rather than only a final result.
These are primary or established learning references for this subject. Check the relevant chapter or specification for the exact topic and version.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises