Delete from End of Doubly Linked List in DSA C++ - Time & Space Complexity
We want to understand how long it takes to remove the last item from a doubly linked list.
How does the time needed change as the list gets bigger?
Analyze the time complexity of the following code snippet.
void deleteFromEnd(Node*& tail) {
if (tail == nullptr) return; // empty list
Node* toDelete = tail;
tail = tail->prev;
if (tail) tail->next = nullptr;
delete toDelete;
}
This code removes the last node from a doubly linked list by updating the tail pointer and freeing memory.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Accessing and updating pointers of the last node.
- How many times: This happens only once per deletion, no loops or recursion.
Removing the last node always takes the same steps, no matter how big the list is.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5 steps |
| 100 | 5 steps |
| 1000 | 5 steps |
Pattern observation: The number of steps stays the same as the list grows.
Time Complexity: O(1)
This means deleting from the end takes a constant amount of time regardless of list size.
[X] Wrong: "Deleting from the end takes longer as the list grows because you have to find the last node."
[OK] Correct: The tail pointer directly points to the last node, so no searching is needed.
Knowing this helps you explain why doubly linked lists are useful for quick deletions at the end, a common interview topic.
"What if we only had a pointer to the head and no tail pointer? How would the time complexity change?"
Practice
tail pointer when you delete the last node from a doubly linked list?Solution
Step 1: Understand the tail pointer role
The tail pointer always points to the last node in the list.Step 2: Effect of deleting the last node
When the last node is deleted, the tail must move to the previous node to remain the last node.Final Answer:
It moves to the previous node of the deleted node -> Option AQuick Check:
Tail updates to previous node after deletion [OK]
- Setting tail to null without checking if list is empty
- Not updating tail pointer after deletion
- Pointing tail to head incorrectly
Solution
Step 1: Identify correct order of operations
First, move tail pointer to previous node, then delete the old last node, and finally set new tail's next to nullptr.Step 2: Match with options
tail = tail->prev; delete tail->next; tail->next = nullptr; correctly moves tail, deletes old node, and updates next pointer.Final Answer:
tail = tail->prev; delete tail->next; tail->next = nullptr; -> Option CQuick Check:
Move tail first, then delete old node [OK]
- Deleting tail before moving pointer causes invalid access
- Not setting tail->next to nullptr after deletion
- Incorrect pointer assignments causing memory leaks
struct Node {
int data;
Node* prev;
Node* next;
};
Node* head = new Node{1, nullptr, nullptr};
Node* second = new Node{2, head, nullptr};
head->next = second;
Node* tail = second;
// Delete last node
Node* temp = tail;
tail = tail->prev;
tail->next = nullptr;
delete temp;
// Print list
Node* curr = head;
while(curr) {
std::cout << curr->data << " ";
curr = curr->next;
}Solution
Step 1: Understand list before deletion
List has two nodes: 1 (head) -> 2 (tail).Step 2: Delete last node and update pointers
Last node (2) is deleted, tail moves to node 1, and tail->next is set to nullptr.Step 3: Print remaining list
Only node 1 remains, so output is "1".Final Answer:
1 -> Option DQuick Check:
Last node deleted, only head remains [OK]
- Printing deleted node due to not updating tail->next
- Assuming list is empty after deletion
- Confusing head and tail pointers
void deleteEnd(Node*& tail) {
delete tail;
tail = tail->prev;
tail->next = nullptr;
}Solution
Step 1: Analyze order of operations
The code deletes tail first, then tries to access tail->prev which is invalid after deletion.Step 2: Correct approach
First move tail pointer to previous node, then delete the old tail node, and update pointers.Final Answer:
Accessing tail->prev after deleting tail causes undefined behavior -> Option BQuick Check:
Delete after pointer update to avoid invalid access [OK]
- Deleting node before updating pointers
- Not checking if tail is nullptr before access
- Confusing order of pointer updates and deletion
Solution
Step 1: Identify the last node and tail pointer
The last node has value 40, tail points to it.Step 2: Move tail pointer to previous node and delete last node
Tail moves to node with value 30, delete node 40, set tail->next to nullptr.Step 3: Final list after deletion
List nodes are now 10 -> 20 -> 30 with tail at 30.Final Answer:
[10, 20, 30] -> Option AQuick Check:
Last node removed, tail updated, list shortened [OK]
- Not updating tail->next to nullptr
- Deleting wrong node or skipping pointer updates
- Assuming list shrinks from head instead of tail
Ready to prove it?
Pass the test and this pattern moves unknown
