Queue Implementation Using Linked List in DSA Python - Time & Space Complexity
We want to understand how fast the main operations of a queue work when it is built using a linked list.
Specifically, how the time to add or remove items changes as the queue grows.
Analyze the time complexity of the following code snippet.
class Node:
def __init__(self, data):
self.data = data
self.next = None
class Queue:
def __init__(self):
self.front = None
self.rear = None
def enqueue(self, data):
new_node = Node(data)
if self.rear is None:
self.front = self.rear = new_node
return
self.rear.next = new_node
self.rear = new_node
def dequeue(self):
if self.front is None:
return None
temp = self.front
self.front = temp.next
if self.front is None:
self.rear = None
return temp.data
This code adds items to the end and removes items from the front of a queue using a linked list.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Adding or removing a single node by updating pointers.
- How many times: Each enqueue or dequeue runs once per operation, no loops inside.
Each enqueue or dequeue operation takes the same amount of time no matter how many items are in the queue.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 1 per enqueue or dequeue |
| 100 | 1 per enqueue or dequeue |
| 1000 | 1 per enqueue or dequeue |
Pattern observation: The time stays constant regardless of queue size.
Time Complexity: O(1)
This means adding or removing an item takes the same short time no matter how big the queue is.
[X] Wrong: "Removing an item from the queue takes longer as the queue grows because it has to move through all nodes."
[OK] Correct: The queue keeps track of the front node, so removing just updates a pointer without searching through nodes.
Knowing that queue operations run in constant time shows you understand efficient data handling, a key skill in many coding challenges.
"What if we did not keep a rear pointer and had to find the end each time we enqueue? How would the time complexity change?"
Practice
Solution
Step 1: Understand queue size limitation in arrays
Arrays have fixed size, so queues implemented with arrays have a maximum capacity.Step 2: Linked list dynamic sizing
Linked lists can grow or shrink dynamically as nodes are added or removed, so no fixed size limit.Final Answer:
Dynamic size without fixed capacity limit -> Option DQuick Check:
Linked list queues grow dynamically = A [OK]
- Thinking linked lists allow faster middle access
- Assuming linked lists always use less memory
- Confusing implementation simplicity
Solution
Step 1: Understand queue initialization
An empty queue using linked list usually has head and tail pointers set to None.Step 2: Identify correct initialization
queue = Queue() with head and tail as None correctly describes a Queue class with head and tail as None, representing empty queue.Final Answer:
queue = Queue() with head and tail as None -> Option CQuick Check:
Empty queue has head and tail None = B [OK]
- Using list [] instead of linked list
- Setting queue to None without structure
- Confusing linked list with array initialization
enqueue(10)
enqueue(20)
dequeue()
enqueue(30)
dequeue()
Print the queue elements from front to rear.
Solution
Step 1: Perform enqueue(10) and enqueue(20)
Queue becomes 10 -> 20 -> null.Step 2: Perform dequeue()
Removes 10, queue is now 20 -> null.Step 3: Perform enqueue(30)
Queue becomes 20 -> 30 -> null.Step 4: Perform dequeue()
Removes 20, queue is now 30 -> null.Final Answer:
30 -> null -> Option AQuick Check:
After operations, queue front is 30 [OK]
- Forgetting to remove front element on dequeue
- Appending dequeue element instead of removing
- Mixing order of operations
def dequeue(self):
if self.head is None:
return None
temp = self.head
self.head = self.head.next
return temp.data
self.tail = None
Solution
Step 1: Analyze the order of statements
The return statement occurs before setting tail to None, so tail update never happens.Step 2: Understand impact on queue state
If last element is dequeued, tail should be set to None to mark empty queue, but it is skipped.Final Answer:
The tail is set to None after return, so never updated -> Option AQuick Check:
Return before tail update skips tail reset [OK]
- Placing return before all updates
- Not resetting tail when queue becomes empty
- Ignoring empty queue check
Solution
Step 1: Understand constraints
No extra data structures allowed, so stack or new list are not options.Step 2: Use recursion to reverse queue
Recursion uses call stack implicitly to dequeue all elements, then enqueue them back in reverse order.Final Answer:
Use recursion to dequeue and enqueue elements in reverse order -> Option BQuick Check:
Recursion reverses queue without extra structures [OK]
- Using extra data structures despite constraints
- Swapping data pairs does not reverse queue order
- Creating new linked list violates no extra structure rule
Ready to prove it?
Pass the test and this pattern moves unknown
