Dequeue Using Linked List in DSA C - Time & Space Complexity
We want to understand how the time to perform operations on a dequeue using a linked list changes as the number of elements grows.
Specifically, how fast can we add or remove items from either end?
Analyze the time complexity of the following code snippet.
// Insert at front
void insertFront(Deque* dq, int value) {
Node* newNode = malloc(sizeof(Node));
newNode->data = value;
newNode->next = dq->front;
dq->front = newNode;
if (dq->rear == NULL) dq->rear = newNode;
}
// Remove from rear
int removeRear(Deque* dq) {
if (dq->rear == NULL) return -1; // empty
int val;
if (dq->front == dq->rear) {
val = dq->front->data;
free(dq->front);
dq->front = NULL;
dq->rear = NULL;
return val;
}
Node* temp = dq->front;
while (temp->next != dq->rear) temp = temp->next;
val = dq->rear->data;
free(dq->rear);
dq->rear = temp;
dq->rear->next = NULL;
return val;
}
This code shows adding an element at the front and removing an element from the rear of a dequeue implemented with a linked list.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The
whileloop inremoveRearthat moves through nodes to find the one before the rear. - How many times: This loop runs once for each node except the last, so up to
n-1times wherenis the number of elements.
As the number of elements grows, the time to remove from rear grows linearly because we must find the node before the last.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 9 steps to find the node before rear |
| 100 | About 99 steps |
| 1000 | About 999 steps |
Pattern observation: The steps increase directly with the number of elements, so doubling elements doubles the work.
Time Complexity: O(n)
This means removing from the rear takes longer as the list grows, roughly proportional to the number of elements.
[X] Wrong: "Removing from the rear is always fast because we have a pointer to the rear node."
[OK] Correct: Even though we have the rear pointer, we must find the node before rear to update its next pointer, which requires walking through the list.
Understanding how linked list operations scale helps you explain trade-offs in data structure choices clearly and confidently.
"What if we kept a pointer to the node before rear? How would that change the time complexity of removing from the rear?"
Practice
Solution
Step 1: Understand linked list flexibility
A linked list can grow or shrink dynamically without needing a fixed size.Step 2: Compare with array limitations
Arrays have fixed size and costly resizing; linked lists allow easy insertion/deletion at both ends.Final Answer:
Dynamic size allows easy insertion and deletion at both ends -> Option AQuick Check:
Linked list dynamic size = Advantage [OK]
- Confusing faster index access with linked list
- Thinking linked lists always use less memory
- Assuming arrays are simpler to implement
Solution
Step 1: Identify node fields for dequeue
A dequeue node needs data and pointers to next and previous nodes for double linking.Step 2: Check pointer types
Correct syntax uses pointers (struct Node*) for next and prev, not int or struct Node directly.Final Answer:
struct Node { int data; struct Node* next; struct Node* prev; }; -> Option DQuick Check:
Double linked node = data + next ptr + prev ptr [OK]
- Using int instead of pointer for next/prev
- Missing prev pointer for dequeue
- Declaring next/prev as struct Node instead of pointer
insertFront(10); insertRear(20); insertFront(5); deleteRear();What will be the state of the dequeue from front to rear after these operations?
Solution
Step 1: Perform insertFront(10) and insertRear(20)
Dequeue: 10 (front) -> 20 (rear)Step 2: Perform insertFront(5) and deleteRear()
After insertFront(5): 5 -> 10 -> 20
After deleteRear(): removes 20, so 5 -> 10Final Answer:
5 -> 10 -> null -> Option AQuick Check:
Front insert adds at front, rear delete removes last [OK]
- Confusing insertFront and insertRear order
- Forgetting to delete rear element
- Mixing up front and rear positions
void deleteFront() {
if (front == NULL) {
printf("Dequeue is empty\n");
return;
}
struct Node* temp = front;
front = front->next;
if (front == NULL) {
rear = NULL;
}
free(temp);
}Solution
Step 1: Analyze pointer updates after deletion
After moving front to front->next, the new front's prev pointer still points to old node.Step 2: Identify missing update
Must set front->prev = NULL to maintain correct double link.Final Answer:
Does not update the prev pointer of new front node -> Option CQuick Check:
Update prev pointer after front deletion [OK]
- Ignoring prev pointer update
- Checking dequeue full in delete function
- Not updating rear when empty (not shown here)
Solution
Step 1: Understand reversing a doubly linked list
Reversing means each node's next and prev pointers must be swapped to reverse direction.Step 2: Swap front and rear pointers
After swapping pointers in nodes, front and rear pointers must also be swapped to reflect new ends.Final Answer:
Swap next and prev pointers of each node, then swap front and rear pointers -> Option BQuick Check:
Swap links + swap ends = reverse dequeue [OK]
- Only swapping front and rear pointers
- Rebuilding list instead of reversing links
- Copying data instead of changing pointers
Ready to prove it?
Pass the test and this pattern moves unknown
