Queue Implementation Using Linked List in DSA C# - Time & Space Complexity
We want to understand how fast the main operations of a queue using a linked list run as the queue grows.
Specifically, how does adding or removing items change with more elements?
Analyze the time complexity of the following code snippet.
public class Node {
public int Data;
public Node Next;
public Node(int data) { Data = data; Next = null; }
}
public class Queue {
private Node front, rear;
public void Enqueue(int data) {
Node newNode = new Node(data);
if (rear == null) {
front = rear = newNode;
return;
}
rear.Next = newNode;
rear = newNode;
}
public int Dequeue() {
if (front == null) throw new InvalidOperationException("Queue is empty");
int value = front.Data;
front = front.Next;
if (front == null) rear = null;
return value;
}
}
This code adds items to the end and removes items from the front of a linked list to form a queue.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Adding or removing a single node by changing pointers.
- How many times: Each operation works on just one node at a time, no loops or recursion inside enqueue or dequeue.
Each enqueue or dequeue does a fixed number of steps regardless of queue size.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5-6 steps per operation |
| 100 | 5-6 steps per operation |
| 1000 | 5-6 steps per operation |
Pattern observation: The number of steps stays about the same no matter how big the queue is.
Time Complexity: O(1)
This means adding or removing an item takes the same short time no matter how many items are in the queue.
[X] Wrong: "Enqueue or dequeue must check all nodes, so it takes longer as the queue grows."
[OK] Correct: The code keeps track of front and rear nodes, so it changes only a few pointers without scanning the whole list.
Knowing that queue operations run in constant time shows you understand efficient data structure design, a key skill in many coding challenges.
"What if we did not keep a rear pointer and only had a front pointer? How would the time complexity of enqueue change?"
Practice
Solution
Step 1: Understand array limitations
Arrays have fixed size, so queues using arrays need resizing or have limited capacity.Step 2: Linked list flexibility
Linked lists grow dynamically by adding nodes, so queues can expand without size limits.Final Answer:
Dynamic size without fixed capacity -> Option AQuick Check:
Linked list queues grow dynamically = D [OK]
- Thinking arrays allow dynamic resizing easily
- Confusing access speed with size flexibility
- Assuming linked lists use less memory always
Solution
Step 1: Check access modifiers
For queue operations, node fields must be accessible; public allows this.Step 2: Class vs struct
Node should be a class to allow reference behavior; struct is value type and not suitable here.Final Answer:
public class Node { public int data; public Node next; } -> Option BQuick Check:
Public class with public fields = A [OK]
- Using struct instead of class for nodes
- Omitting public keyword causing access errors
- Making fields private without accessors
Queue queue = new Queue(); queue.Enqueue(10); queue.Enqueue(20); queue.Enqueue(30); int first = queue.Dequeue(); queue.Enqueue(40); int second = queue.Dequeue(); Console.WriteLine(first + ", " + second);
Solution
Step 1: Trace enqueue and dequeue operations
Enqueue 10, 20, 30 adds these in order. Dequeue removes 10 (first). Enqueue 40 adds at end. Dequeue removes 20 (next).Step 2: Identify values of first and second
first = 10, second = 20. Output prints "10, 20".Final Answer:
10, 20 -> Option CQuick Check:
FIFO order = 10, 20 [OK]
- Confusing enqueue and dequeue order
- Assuming dequeue removes last element
- Mixing values after enqueue and dequeue
public int Dequeue() {
if (front == null) throw new InvalidOperationException("Queue is empty");
int value = front.data;
front = front.next;
return value;
}Solution
Step 1: Analyze dequeue when one element remains
If front moves to null after removing last node, rear still points to old node, causing inconsistency.Step 2: Fix by setting rear to null when queue is empty
When front is null, rear must also be set to null to indicate empty queue properly.Final Answer:
Should set rear to null when queue becomes empty -> Option AQuick Check:
Rear must be null if front is null [OK]
- Ignoring rear pointer update on empty queue
- Throwing wrong exception type
- Unnecessary null assignment to front.next
ReverseQueue() that reverses the order of elements in a linked list queue without using extra data structures. Which approach is best?Solution
Step 1: Understand reversing linked list nodes
Changing next pointers of nodes reverses the linked list in place without extra space.Step 2: Compare with other options
Using stack or new queue uses extra space; swapping data is inefficient and error-prone.Final Answer:
Iteratively reverse the linked list nodes by changing next pointers -> Option DQuick Check:
In-place reversal changes pointers = B [OK]
- Using extra data structures despite constraint
- Swapping data instead of pointers
- Creating new queues unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
