What if you could move backward in a list as easily as forward, saving time and effort?
Why Doubly Linked List Over Singly Linked List in DSA Typescript - The Real Reason
Imagine you have a long chain of paper clips linked together. You want to find a specific clip and sometimes move backward or forward along the chain. If you can only move forward, it takes a lot of time to find or change clips near the start or end.
Using a singly linked list is like only being able to move forward along the chain. If you want to go backward, you must start from the beginning again. This makes some tasks slow and frustrating, especially when you need to delete or insert clips near the end or move backward often.
A doubly linked list adds a link to the previous clip, so you can move both forward and backward easily. This makes finding, inserting, or deleting clips faster and simpler because you don't have to start from the beginning every time.
class Node { value: number; next: Node | null; constructor(value: number) { this.value = value; this.next = null; } } // To delete a node, you must find the previous node by starting from head.
class Node { value: number; next: Node | null; prev: Node | null; constructor(value: number) { this.value = value; this.next = null; this.prev = null; } } // You can delete a node directly using prev pointer without starting from head.
It enables efficient two-way navigation and easier updates in the list, making your programs faster and more flexible.
Think of a music playlist where you want to go to the next or previous song quickly. A doubly linked list lets you move back and forth smoothly without restarting from the first song every time.
Doubly linked lists allow moving forward and backward easily.
They make insertion and deletion faster by using previous links.
They improve efficiency in tasks needing two-way navigation.
Practice
doubly linked list over a singly linked list in a program?Solution
Step 1: Understand traversal capabilities
A singly linked list allows moving forward only, while a doubly linked list allows moving forward and backward.Step 2: Compare memory and complexity
Doubly linked lists use more memory and are more complex but provide two-way traversal.Final Answer:
Because it allows traversal in both directions easily -> Option BQuick Check:
Two-way traversal = A [OK]
- Thinking doubly linked lists use less memory
- Confusing simplicity with singly linked lists
- Assuming singly linked lists allow backward traversal
Solution
Step 1: Identify required pointers for doubly linked list node
A doubly linked list node must have bothnextandprevpointers, which can be null if no neighbor exists.Step 2: Check TypeScript syntax for nullable pointers
UsingNode | nullcorrectly allows for the end nodes to have null pointers.Final Answer:
class Node { value: number; next: Node | null; prev: Node | null; } -> Option CQuick Check:
Doubly linked node needs next and prev with nulls [OK]
- Omitting the prev pointer
- Not allowing null for next or prev
- Using only one pointer like singly linked list
class Node {
value: number;
next: Node | null = null;
prev: Node | null = null;
constructor(value: number) { this.value = value; }
}
class DoublyLinkedList {
head: Node | null = null;
insertFront(value: number) {
const newNode = new Node(value);
if (this.head) {
newNode.next = this.head;
this.head.prev = newNode;
}
this.head = newNode;
}
}
const list = new DoublyLinkedList();
list.insertFront(10);
list.insertFront(20);
list.insertFront(30);
let current = list.head;
const result = [];
while (current) {
result.push(current.value);
current = current.next;
}
console.log(result);
What will be printed?Solution
Step 1: Trace insertFront calls
First insert 10: list is 10. Then insert 20 at front: list is 20 -> 10. Then insert 30 at front: list is 30 -> 20 -> 10.Step 2: Traverse from head to next
Starting at head (30), next is 20, then 10, then null. So collected values are [30, 20, 10].Final Answer:
[30, 20, 10] -> Option DQuick Check:
Insert front reverses order = [30, 20, 10] [OK]
- Assuming insertion appends at end
- Mixing order of traversal
- Ignoring prev pointer effects
deleteLast() {
if (!this.head) return;
let current = this.head;
while (current.next) {
current = current.next;
}
current.prev.next = null;
}
What is the bug here?Solution
Step 1: Analyze deletion logic
The code moves to the last node by following next pointers. Then it setscurrent.prev.next = nullto remove last node.Step 2: Check edge case for single node list
If list has only one node,current.previs null, socurrent.prev.nextcauses error.Final Answer:
It does not handle the case when list has only one node -> Option AQuick Check:
Single node list needs special case [OK]
- Ignoring single node edge case
- Assuming prev is always non-null
- Confusing next and prev pointers
Solution
Step 1: Understand backward traversal need
Backward traversal means moving from a node to its previous nodes efficiently.Step 2: Compare data structures for backward traversal
Singly linked lists do not have backward pointers. Arrays allow random access but not linked traversal. Circular singly linked lists loop but do not support backward traversal. Doubly linked lists have prev pointers for efficient backward moves.Final Answer:
Doubly linked list because it allows backward traversal efficiently -> Option AQuick Check:
Backward traversal needs prev pointers [OK]
- Choosing singly linked list for backward traversal
- Confusing arrays with linked lists
- Thinking circular singly linked lists support backward moves
Ready to prove it?
Pass the test and this pattern moves unknown
