A queue is a First-In-First-Out (FIFO) data structure, while a deque allows adding and removing elements from both ends efficiently. This post explores queues and deques in Python, their operations, use cases, and provides practical examples and problems.
Overview
A queue is a First-In-First-Out (FIFO) data structure. A deque (double-ended queue) allows adding/removing from both ends efficiently.
In Python:
- Use
collections.deque
for both queue and deque behavior - Use
queue.Queue
for thread-safe queues (multithreading)
🧩 Visualizing Queues and Deques
Queue Operations (FIFO)
graph LR
Initial[Initial: empty]
E1[Enqueue 1]
E2[Enqueue 2]
E3[Enqueue 3]
D1[Dequeue returns 1]
D2[Dequeue returns 2]
P1[Peek returns 3]
Initial --> E1 --> E2 --> E3 --> D1 --> D2 --> P1
Q1[Queue: 1]
Q2[Queue: 1,2]
Q3[Queue: 1,2,3]
Q4[Queue: 2,3]
Q5[Queue: 3]
Q6[Queue: 3]
E1 -.-> Q1
E2 -.-> Q2
E3 -.-> Q3
D1 -.-> Q4
D2 -.-> Q5
P1 -.-> Q6
style Initial fill:#f9f9f9
style P1 fill:#99ff99
Deque Operations (Double-ended)
graph LR
Start[Initial: empty]
A1[Append 1]
AL2[Appendleft 2]
A3[Append 3]
P1[Pop returns 3]
PL1[Popleft returns 2]
Start --> A1 --> AL2 --> A3 --> P1 --> PL1
D1[Deque: 1]
D2[Deque: 2,1]
D3[Deque: 2,1,3]
D4[Deque: 2,1]
D5[Deque: 1]
A1 -.-> D1
AL2 -.-> D2
A3 -.-> D3
P1 -.-> D4
PL1 -.-> D5
style Start fill:#f9f9f9
style PL1 fill:#99ff99
🛠️ How to Use (Python)
# Basic queue and deque operations in Python
- Use collections.deque for efficient queue and deque behavior
from collections import deque
q = deque()
q.append(1) # Enqueue 1 at the end
q.popleft() # Dequeue from the front
q.appendleft(2) # Add 2 to the front
q.pop() # Remove from the end
# All operations above are O(1)
# Example:
q = deque()
q.append(10)
q.append(20)
q.append(30)
print(q.popleft()) # Output: 10
print(q) # Output: deque([20, 30])
🧩 Moving Average Flow
graph TD
Start[Start: window_size = 3]
Step1[Step 1: val=1 to q=1 avg=1.0]
Step2[Step 2: val=10 to q=1,10 avg=5.5]
Step3[Step 3: val=3 to q=1,10,3 avg=4.67]
Step4[Step 4: val=5 to q=10,3,5 avg=6.0]
Result[Result: Moving averages calculated]
Start --> Step1 --> Step2 --> Step3 --> Step4 --> Result
style Result fill:#99ff99
🧩 Moving Average Step-by-Step
Suppose size = 3, values = [1, 10, 3, 5]
Step | val | q before | q after | sum | len(q) | avg |
---|---|---|---|---|---|---|
1 | 1 | [] | [1] | 1 | 1 | 1.0 |
2 | 10 | [1] | [1,10] | 11 | 2 | 5.5 |
3 | 3 | [1,10] | [1,10,3] | 14 | 3 | 4.67 |
4 | 5 | [1,10,3] | [10,3,5] | 18 | 3 | 6.0 |
- When q exceeds size, remove oldest element.
📘 Sample Problem 1: Moving Average from Data Stream
Design a class that finds the moving average of the last
k
elements.
from collections import deque
# This class maintains a moving average of the last k elements.
class MovingAverage:
def __init__(self, size):
self.q = deque() # Store the last k elements
self.k = size
self.sum = 0 # Keep running sum
def next(self, val):
self.q.append(val)
self.sum += val
if len(self.q) > self.k:
self.sum -= self.q.popleft() # Remove oldest if over size
return self.sum / len(self.q) # Return current average
# Time complexity: O(1) per operation, Space complexity: O(k)
# Example:
ma = MovingAverage(3)
print(ma.next(1)) # Output: 1.0
print(ma.next(10)) # Output: 5.5
print(ma.next(3)) # Output: 4.67
print(ma.next(5)) # Output: 6.0
🧩 Sliding Window Maximum Flow
graph TD
Start[Start: nums=1,3,-1,-3,5,3,6,7 k=3]
Step1[Step 1: i=0 q=0 res=empty]
Step2[Step 2: i=1 q=1 res=empty]
Step3[Step 3: i=2 q=1,2 res=3]
Step4[Step 4: i=3 q=1,2,3 res=3,3]
Step5[Step 5: i=4 q=4 res=3,3,5]
Step6[Step 6: i=5 q=4,5 res=3,3,5,5]
Step7[Step 7: i=6 q=6 res=3,3,5,5,6]
Step8[Step 8: i=7 q=7 res=3,3,5,5,6,7]
Result[Result: 3,3,5,5,6,7]
Start --> Step1 --> Step2 --> Step3 --> Step4 --> Step5 --> Step6 --> Step7 --> Step8 --> Result
style Result fill:#99ff99
Suppose nums = [1, 3, -1, -3, 5, 3, 6, 7], k = 3
i | nums[i] | q before | nums[q[-1]] < nums[i]? | q after | q[0] == i-k? | res |
---|---|---|---|---|---|---|
0 | 1 | [] | - | [0] | 0 == -3? | [] |
1 | 3 | [0] | 1 < 3 | [1] | 1 == -2? | [] |
2 | -1 | [1] | 3 < -1 | [1,2] | 1 == -1? | [3] |
3 | -3 | [1,2] | -1 < -3 | [1,2,3] | 1 == 0? | [3] |
4 | 5 | [1,2,3] | -3 < 5, -1 < 5, 3 < 5 | [4] | 4 == 1? | [3,3] |
5 | 3 | [4] | 5 < 3 | [4,5] | 4 == 2? | [3,3,5] |
6 | 6 | [4,5] | 3 < 6, 5 < 6 | [6] | 6 == 3? | [3,3,5,5] |
7 | 7 | [6] | 6 < 7 | [7] | 7 == 4? | [3,3,5,5,6] |
- Result: [3, 3, 5, 5, 6, 7]
📘 Sample Problem 2: Sliding Window Maximum
Given an array
nums
and window sizek
, return max of each window.
from collections import deque
# This function finds the maximum in each sliding window of size k.
def max_sliding_window(nums, k):
q = deque() # Store indices of useful elements
res = []
for i, n in enumerate(nums):
while q and nums[q[-1]] < n:
q.pop() # Remove indices whose values are less than current
q.append(i)
if q[0] == i - k:
q.popleft() # Remove indices out of the window
if i >= k - 1:
res.append(nums[q[0]]) # The front is the max in window
return res
# Time complexity: O(n), Space complexity: O(k)
# Example:
nums = [1, 3, -1, -3, 5, 3, 6, 7]
k = 3
print(max_sliding_window(nums, k)) # Output: [3, 3, 5, 5, 6, 7]
🔁 Variants
- Circular queue
- Monotonic queue (for range min/max)
- Double-ended queue (deque for palindrome checks)
Comments
Add a Comment
Please be mindful
There are currently no comments on this article, be the first to add one below