Doubly Linked List Structure and Node Design in DSA C++ - Time & Space Complexity
We want to understand how the time to create and link nodes in a doubly linked list grows as we add more nodes.
How does the work increase when the list gets longer?
Analyze the time complexity of the following code snippet.
struct Node {
int data;
Node* prev;
Node* next;
Node(int val) : data(val), prev(nullptr), next(nullptr) {}
};
void append(Node*& head, int val) {
Node* newNode = new Node(val);
if (!head) {
head = newNode;
return;
}
Node* temp = head;
while (temp->next) {
temp = temp->next;
}
temp->next = newNode;
newNode->prev = temp;
}
This code creates a doubly linked list node and appends a new node at the end of the list.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop that moves through the list to find the last node.
- How many times: It runs once for each node already in the list, so if there are n nodes, it runs about n times.
As the list grows, the time to add a new node grows roughly in a straight line with the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps to find the end |
| 100 | About 100 steps to find the end |
| 1000 | About 1000 steps to find the end |
Pattern observation: The work increases directly with the number of nodes, so doubling nodes doubles the work.
Time Complexity: O(n)
This means adding a node takes longer as the list gets longer, growing in a straight line with the list size.
[X] Wrong: "Appending a node always takes the same time no matter how long the list is."
[OK] Correct: Because the code must walk through all existing nodes to find the end, the time grows with the list length.
Understanding how node traversal affects time helps you explain and improve linked list operations clearly in interviews.
"What if we kept a pointer to the tail node? How would the time complexity of appending change?"
Practice
Solution
Step 1: Understand node pointers in doubly linked list
Each node has two pointers: one to the next node and one to the previous node.Step 2: Compare traversal capabilities
This allows moving forward and backward through the list, unlike singly linked lists which only allow forward traversal.Final Answer:
It allows traversal in both forward and backward directions. -> Option DQuick Check:
Doubly linked list = two-way traversal [OK]
- Thinking it uses less memory than singly linked list
- Assuming it has only one pointer per node
- Believing it can only traverse forward
Solution
Step 1: Check pointer usage for next and prev
In a doubly linked list, next and prev must be pointers to Node, so Node* next and Node* prev are correct.Step 2: Identify incorrect declarations
struct Node { int data; Node next; Node prev; }; uses Node next and Node prev (not pointers), C uses int prev, and D uses int for both next and prev, which is incorrect.Final Answer:
struct Node { int data; Node* next; Node* prev; }; -> Option AQuick Check:
Pointers for next and prev = struct Node { int data; Node* next; Node* prev; }; [OK]
- Using Node instead of Node* for next and prev
- Using int type for pointers
- Missing pointer symbols
struct Node {
int data;
Node* next;
Node* prev;
};
Node* head = nullptr;
Node* newNode = new Node{10, nullptr, nullptr};
newNode->next = head;
if (head != nullptr) {
head->prev = newNode;
}
head = newNode;
// What is the data in head->next after insertion?Solution
Step 1: Analyze initial head value
Initially, head is nullptr, meaning the list is empty.Step 2: After insertion, newNode->next points to old head (nullptr)
Since head was nullptr, newNode->next is set to nullptr, so head->next is nullptr after insertion.Final Answer:
nullptr -> Option AQuick Check:
Empty list insertion sets next to nullptr [OK]
- Assuming head->next has data 10
- Thinking head->next is undefined or garbage
- Ignoring initial nullptr head
struct Node {
int data;
Node* next;
Node* prev;
};
void insertEnd(Node*& head, int val) {
Node* newNode = new Node{val, nullptr, nullptr};
if (head == nullptr) {
head = newNode;
return;
}
Node* temp = head;
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = newNode;
newNode->prev = nullptr;
}Solution
Step 1: Check newNode's prev pointer assignment
After finding the last node (temp), newNode is added after temp, so newNode->prev must point to temp.Step 2: Identify incorrect assignment
Code sets newNode->prev = nullptr, which breaks backward link; it should be newNode->prev = temp.Final Answer:
newNode->prev should point to temp, not nullptr. -> Option CQuick Check:
Prev pointer links new node to last node [OK]
- Setting newNode->prev to nullptr instead of last node
- Passing head by value losing list updates
- Incorrect initialization of temp pointer
Solution
Step 1: Understand node removal in doubly linked list
To remove a node, the previous node's next pointer must skip the node and point to node's next.Step 2: Update next node's prev pointer
Similarly, the next node's prev pointer must skip the node and point to node's prev.Final Answer:
Set node's prev->next to node's next and node's next->prev to node's prev. -> Option BQuick Check:
Prev and next pointers bypass deleted node [OK]
- Not updating both prev and next pointers
- Setting wrong pointers to nullptr
- Deleting node without fixing links
Ready to prove it?
Pass the test and this pattern moves unknown
