Create and Initialize Doubly Linked List in DSA Javascript - Time & Space Complexity
When we create and initialize a doubly linked list, we want to know how the time needed grows as we add more items.
We ask: How long does it take to build the list as it gets bigger?
Analyze the time complexity of the following code snippet.
class Node {
constructor(value) {
this.value = value;
this.next = null;
this.prev = null;
}
}
function createDoublyLinkedList(arr) {
let head = null;
let tail = null;
for (let val of arr) {
const newNode = new Node(val);
if (!head) {
head = newNode;
tail = newNode;
} else {
tail.next = newNode;
newNode.prev = tail;
tail = newNode;
}
}
return head;
}
This code builds a doubly linked list from an array by adding nodes one by one.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through each element of the input array once.
- How many times: Exactly once per element, so n times if the array has n items.
Each new item in the array causes one new node to be created and linked.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 node creations and linkings |
| 100 | About 100 node creations and linkings |
| 1000 | About 1000 node creations and linkings |
Pattern observation: The work grows directly with the number of items; doubling items doubles the work.
Time Complexity: O(n)
This means the time to create the list grows in a straight line with the number of items.
[X] Wrong: "Creating a doubly linked list takes more than linear time because of the extra pointers."
[OK] Correct: Each node is created once and linked in constant time; the extra pointers do not add extra loops or repeated work.
Understanding this helps you explain how data structures build up efficiently, a key skill in many coding challenges.
"What if we added a nested loop to link nodes in pairs? How would the time complexity change?"
Practice
Solution
Step 1: Understand node structure in doubly linked list
Each node in a doubly linked list has two pointers: one to the next node and one to the previous node.Step 2: Compare with singly linked list
Singly linked list nodes have only one pointer to the next node, so they cannot go backward.Final Answer:
A doubly linked list has nodes with pointers to both previous and next nodes. -> Option AQuick Check:
Doubly linked list = two pointers per node [OK]
- Thinking doubly linked lists use arrays
- Believing doubly linked lists only go forward
- Confusing pointers with data storage
Solution
Step 1: Identify required pointers for doubly linked list node
A doubly linked list node needs both 'prev' and 'next' pointers initialized to null.Step 2: Check constructor parameters and properties
class Node { constructor(data) { this.data = data; this.prev = null; this.next = null; } } correctly defines 'data', 'prev', and 'next' properties in the constructor.Final Answer:
class Node { constructor(data) { this.data = data; this.prev = null; this.next = null; } } -> Option BQuick Check:
Node needs prev and next pointers [OK]
- Omitting the prev pointer
- Using wrong pointer names like left/right
- Using different property names for data
class Node {
constructor(data) {
this.data = data;
this.prev = null;
this.next = null;
}
}
class DoublyLinkedList {
constructor() {
this.head = null;
this.tail = null;
}
append(data) {
const newNode = new Node(data);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
newNode.prev = this.tail;
this.tail = newNode;
}
}
}
const list = new DoublyLinkedList();
list.append(1);
list.append(2);
list.append(3);
let current = list.head;
const result = [];
while (current) {
result.push(current.data);
current = current.next;
}
console.log(result);Solution
Step 1: Append nodes 1, 2, 3 to the list
Each append adds a new node at the tail, linking prev and next pointers correctly.Step 2: Traverse from head to tail collecting data
Starting at head (1), moving next collects 1, then 2, then 3, then stops at null.Final Answer:
[1, 2, 3] -> Option DQuick Check:
Traversal from head collects [1, 2, 3] [OK]
- Confusing traversal direction
- Not updating tail pointer on append
- Pushing null values instead of data
class Node {
constructor(data) {
this.data = data;
this.prev = null;
this.next = null;
}
}
class DoublyLinkedList {
constructor() {
this.head = null;
this.tail = null;
}
append(data) {
const newNode = new Node(data);
if (!this.head) {
this.head = newNode;
this.tail = newNode;
} else {
this.tail.next = newNode;
this.tail.prev = newNode;
this.tail = newNode;
}
}
}Solution
Step 1: Analyze pointer updates in append method
When adding newNode, the previous tail's next should point to newNode, and newNode's prev should point to old tail.Step 2: Identify incorrect pointer assignment
The code incorrectly sets 'this.tail.prev = newNode;' which wrongly changes the old tail's prev pointer instead of newNode's prev pointer.Final Answer:
The line 'this.tail.prev = newNode;' should be 'newNode.prev = this.tail;'. -> Option CQuick Check:
Correct prev pointer must link newNode to old tail [OK]
- Swapping prev and next pointers
- Not updating newNode.prev correctly
- Forgetting to update tail pointer
Solution
Step 1: Append values in order to the list
Using a for-of loop appends 10, then 20, then 30, building the list head to tail.Step 2: Traverse backward from tail using prev pointer
Starting at tail (30), moving prev prints 30, 20, 10 in reverse order.Final Answer:
const list = new DoublyLinkedList(); for (const val of [10, 20, 30]) list.append(val); let current = list.tail; while (current) { console.log(current.data); current = current.prev; } -> Option AQuick Check:
Backward traversal uses tail and prev pointer [OK]
- Traversing backward from head
- Using next pointer to go backward
- Appending values in reverse order but traversing forward
Ready to prove it?
Pass the test and this pattern moves unknown
