Bird
Raised Fist0
DSA Typescriptprogramming

Doubly Linked List Structure and Node Design in DSA Typescript

Choose your learning style10 modes available
Mental Model
A doubly linked list is a chain of nodes where each node knows both its neighbor before and after it.
Analogy: Imagine a train where each carriage has a connector to the carriage in front and the one behind, so you can move forward or backward easily.
null ← [head]1↔2↔3[tail] → null
Dry Run Walkthrough
Input: list: empty, insert nodes with values 1, 2, 3 in order
Goal: Build a doubly linked list with nodes 1, 2, 3 connected forward and backward
Step 1: Create first node with value 1; head and tail point to it
null ← [head/tail]1 → null
Why: We start the list with one node, so head and tail are the same
Step 2: Create second node with value 2; link it after node 1; update tail
null ← 1 ↔ [tail]2 → null
Why: Add node 2 after node 1 and update tail to new last node
Step 3: Create third node with value 3; link it after node 2; update tail
null ← 1 ↔ 2 ↔ [tail]3 → null
Why: Add node 3 after node 2 and update tail to new last node
Result:
null ← 1 ↔ 2 ↔ 3 → null
Annotated Code
DSA Typescript
class Node {
  value: number;
  prev: Node | null;
  next: Node | null;

  constructor(value: number) {
    this.value = value;
    this.prev = null;
    this.next = null;
  }
}

class DoublyLinkedList {
  head: Node | null;
  tail: Node | null;

  constructor() {
    this.head = null;
    this.tail = null;
  }

  insert(value: number): void {
    const newNode = new Node(value);
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
      return;
    }
    this.tail!.next = newNode; // link current tail to new node
    newNode.prev = this.tail; // link new node back to current tail
    this.tail = newNode; // update tail to new node
  }

  printForward(): void {
    let curr = this.head;
    let result = '';
    while (curr) {
      result += curr.value + (curr.next ? ' ↔ ' : ' → null');
      curr = curr.next;
    }
    console.log(result);
  }

  printBackward(): void {
    let curr = this.tail;
    let result = '';
    while (curr) {
      result += curr.value + (curr.prev ? ' ↔ ' : ' ← null');
      curr = curr.prev;
    }
    console.log(result);
  }
}

// Driver code
const list = new DoublyLinkedList();
list.insert(1);
list.insert(2);
list.insert(3);
list.printForward();
list.printBackward();
if (!this.head) { this.head = newNode; this.tail = newNode; return; }
initialize head and tail when list is empty
this.tail!.next = newNode;
link current tail's next to new node
newNode.prev = this.tail;
link new node's prev back to current tail
this.tail = newNode;
update tail pointer to new node
while (curr) { result += curr.value + (curr.next ? ' ↔ ' : ' → null'); curr = curr.next; }
traverse forward printing values with arrows
while (curr) { result += curr.value + (curr.prev ? ' ↔ ' : ' ← null'); curr = curr.prev; }
traverse backward printing values with arrows
OutputSuccess
1 ↔ 2 ↔ 3 → null 3 ↔ 2 ↔ 1 ← null
Complexity Analysis
Time: O(n) for printing because we visit each node once; O(1) for insertion at tail because we keep tail pointer
Space: O(n) for storing n nodes in the list
vs Alternative: Compared to singly linked list, doubly linked list uses extra space for prev pointers but allows backward traversal and easier node removal
Edge Cases
empty list
insertion sets head and tail to new node
DSA Typescript
if (!this.head) { this.head = newNode; this.tail = newNode; return; }
single node list
new node links after tail and tail updates correctly
DSA Typescript
this.tail!.next = newNode;
When to Use This Pattern
When you need to move forward and backward through a list easily, use a doubly linked list because each node links both ways.
Common Mistakes
Mistake: Forgetting to update the new node's prev pointer when inserting
Fix: Always set newNode.prev = current tail to maintain backward link
Mistake: Not updating tail pointer after insertion
Fix: Set tail = newNode after linking to keep tail accurate
Summary
It stores nodes linked both forward and backward for easy two-way traversal.
Use it when you want to move in both directions or delete nodes easily.
Remember each node has two links: one to the next and one to the previous node.

Practice

(1/5)
1. What is the main difference between a doubly linked list node and a singly linked list node?
easy
A. A doubly linked list node has pointers to both the previous and next nodes.
B. A doubly linked list node stores data in a different format.
C. A doubly linked list node can only point to the next node.
D. A doubly linked list node does not store any data.

Solution

  1. Step 1: Understand node pointers in singly linked list

    A singly linked list node has only one pointer to the next node.
  2. Step 2: Understand node pointers in doubly linked list

    A doubly linked list node has two pointers: one to the previous node and one to the next node.
  3. Final Answer:

    A doubly linked list node has pointers to both the previous and next nodes. -> Option A
  4. Quick Check:

    Doubly linked list nodes have two pointers [OK]
Hint: Remember: doubly linked means two directions [OK]
Common Mistakes:
  • Thinking doubly linked nodes only point forward
  • Confusing data storage with pointer structure
  • Assuming doubly linked nodes do not store data
2. Which of the following is the correct TypeScript syntax to define a doubly linked list node class with data of type number?
easy
A. class Node { data: number; next: Node | null; prev: Node | null; constructor(data: number) { this.data = data; this.next = null; this.prev = null; } }
B. class Node { data: number; next: Node; prev: Node; constructor(data: number) { this.data = data; this.next = null; this.prev = null; } }
C. class Node { data: number; next: Node; prev: Node; constructor(data: number) { this.data = data; } }
D. class Node { data: number; next: null; prev: null; constructor(data: number) { this.data = data; this.next = null; this.prev = null; } }

Solution

  1. Step 1: Check property types for next and prev

    Since next and prev can be null initially, their types must allow null (Node | null).
  2. Step 2: Verify constructor initializes all properties

    The constructor sets data and initializes next and prev to null correctly.
  3. Final Answer:

    class Node { data: number; next: Node | null; prev: Node | null; constructor(data: number) { this.data = data; this.next = null; this.prev = null; } } -> Option A
  4. Quick Check:

    Allow null for next and prev in TypeScript [OK]
Hint: Use 'Node | null' for nullable pointers [OK]
Common Mistakes:
  • Not allowing next and prev to be null
  • Forgetting to initialize next and prev in constructor
  • Setting next and prev types incorrectly
3. What will be the output of the following TypeScript code snippet?
class Node {
  data: number;
  next: Node | null;
  prev: Node | null;
  constructor(data: number) {
    this.data = data;
    this.next = null;
    this.prev = null;
  }
}

const node1 = new Node(10);
const node2 = new Node(20);
node1.next = node2;
node2.prev = node1;

console.log(node1.next?.data);
console.log(node2.prev?.data);
medium
A. Error at runtime
B. 10\n20
C. undefined\nundefined
D. 20\n10

Solution

  1. Step 1: Trace node1.next and node2.prev assignments

    node1.next points to node2, so node1.next.data is 20. node2.prev points to node1, so node2.prev.data is 10.
  2. Step 2: Check console.log outputs

    console.log(node1.next?.data) prints 20, console.log(node2.prev?.data) prints 10.
  3. Final Answer:

    20 10 -> Option D
  4. Quick Check:

    next and prev pointers give 20 and 10 respectively [OK]
Hint: Follow next and prev pointers to get data [OK]
Common Mistakes:
  • Confusing which node data is printed
  • Ignoring optional chaining and assuming errors
  • Mixing up prev and next pointers
4. Identify the error in the following TypeScript code for a doubly linked list node and select the fix.
class Node {
  data: number;
  next: Node;
  prev: Node;
  constructor(data: number) {
    this.data = data;
    this.next = null;
    this.prev = null;
  }
}
medium
A. Change data type from number to any.
B. Remove the constructor to fix the error.
C. Change next and prev types to 'Node | null' to allow null assignment.
D. Initialize next and prev with new Node() instead of null.

Solution

  1. Step 1: Analyze type declarations and assignments

    next and prev are typed as Node but assigned null, which is invalid in TypeScript.
  2. Step 2: Fix type to allow null

    Changing next and prev types to 'Node | null' allows null assignment and fixes the error.
  3. Final Answer:

    Change next and prev types to 'Node | null' to allow null assignment. -> Option C
  4. Quick Check:

    Nullable pointers need 'Node | null' type [OK]
Hint: Allow null in pointer types to avoid errors [OK]
Common Mistakes:
  • Leaving next and prev as non-nullable types
  • Trying to assign new Node() without data
  • Removing constructor unnecessarily
5. You want to insert a new node with data 30 between two existing nodes in a doubly linked list: nodeA and nodeB, where nodeA.next = nodeB and nodeB.prev = nodeA. Which sequence of pointer updates correctly inserts the new node?
hard
A. nodeA.next = newNode; nodeB.prev = newNode; newNode.next = nodeB; newNode.prev = nodeA;
B. newNode.prev = nodeA; newNode.next = nodeB; nodeA.next = newNode; nodeB.prev = newNode;
C. newNode.next = nodeA; newNode.prev = nodeB; nodeA.prev = newNode; nodeB.next = newNode;
D. nodeA.prev = newNode; nodeB.next = newNode; newNode.prev = nodeB; newNode.next = nodeA;

Solution

  1. Step 1: Set newNode pointers to link between nodeA and nodeB

    newNode.prev must point to nodeA and newNode.next must point to nodeB to fit between them.
  2. Step 2: Update nodeA and nodeB pointers to include newNode

    nodeA.next should point to newNode and nodeB.prev should point to newNode to complete the insertion.
  3. Final Answer:

    newNode.prev = nodeA; newNode.next = nodeB; nodeA.next = newNode; nodeB.prev = newNode; -> Option B
  4. Quick Check:

    Link newNode between nodeA and nodeB correctly [OK]
Hint: Link newNode pointers first, then update neighbors [OK]
Common Mistakes:
  • Mixing up prev and next pointers
  • Updating neighbors before setting newNode pointers
  • Reversing nodeA and nodeB in assignments
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard