0
0
JavascriptHow-ToBeginner · 4 min read

How to Implement Doubly Linked List in JavaScript Easily

To implement a doubly linked list in JavaScript, create a Node class with value, next, and prev properties, then build a DoublyLinkedList class to manage nodes with methods like append and remove. This structure allows traversal in both directions efficiently.
📐

Syntax

A doubly linked list uses two classes: Node and DoublyLinkedList.

  • Node holds the data and links to the next and previous nodes.
  • DoublyLinkedList manages the list with a head and tail, and methods to add or remove nodes.
javascript
class Node {
  constructor(value) {
    this.value = value;
    this.next = null;
    this.prev = null;
  }
}

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

  append(value) {
    const newNode = new Node(value);
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      newNode.prev = this.tail;
      this.tail = newNode;
    }
  }

  remove(value) {
    let current = this.head;
    while (current) {
      if (current.value === value) {
        if (current.prev) {
          current.prev.next = current.next;
        } else {
          this.head = current.next;
        }
        if (current.next) {
          current.next.prev = current.prev;
        } else {
          this.tail = current.prev;
        }
        return true;
      }
      current = current.next;
    }
    return false;
  }
}
💻

Example

This example shows how to create a doubly linked list, add nodes, remove a node, and print the list forward and backward.

javascript
class Node {
  constructor(value) {
    this.value = value;
    this.next = null;
    this.prev = null;
  }
}

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

  append(value) {
    const newNode = new Node(value);
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      newNode.prev = this.tail;
      this.tail = newNode;
    }
  }

  remove(value) {
    let current = this.head;
    while (current) {
      if (current.value === value) {
        if (current.prev) {
          current.prev.next = current.next;
        } else {
          this.head = current.next;
        }
        if (current.next) {
          current.next.prev = current.prev;
        } else {
          this.tail = current.prev;
        }
        return true;
      }
      current = current.next;
    }
    return false;
  }

  printForward() {
    let current = this.head;
    let result = '';
    while (current) {
      result += current.value + ' ';
      current = current.next;
    }
    console.log(result.trim());
  }

  printBackward() {
    let current = this.tail;
    let result = '';
    while (current) {
      result += current.value + ' ';
      current = current.prev;
    }
    console.log(result.trim());
  }
}

const list = new DoublyLinkedList();
list.append(10);
list.append(20);
list.append(30);
list.printForward();  // Output: 10 20 30
list.printBackward(); // Output: 30 20 10
list.remove(20);
list.printForward();  // Output: 10 30
list.printBackward(); // Output: 30 10
Output
10 20 30 30 20 10 10 30 30 10
⚠️

Common Pitfalls

Common mistakes include:

  • Not updating prev and next pointers correctly when adding or removing nodes.
  • Forgetting to update head or tail when the first or last node changes.
  • Not handling empty list cases properly.

Always check if the node to remove is the head or tail and update pointers accordingly.

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

  // Wrong: Does not update prev pointer of new node
  append(value) {
    const newNode = { value, next: null, prev: null };
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      // Missing: newNode.prev = this.tail;
      this.tail = newNode;
    }
  }
}

// Correct append method updates prev pointer
class DoublyLinkedListRight {
  constructor() {
    this.head = null;
    this.tail = null;
  }

  append(value) {
    const newNode = { value, next: null, prev: null };
    if (!this.head) {
      this.head = newNode;
      this.tail = newNode;
    } else {
      this.tail.next = newNode;
      newNode.prev = this.tail;
      this.tail = newNode;
    }
  }
}
📊

Quick Reference

  • Node: Holds value, next, and prev.
  • append(value): Adds node to the end, updates tail.
  • remove(value): Finds and removes node, updates neighbors and head/tail if needed.
  • Always update prev and next pointers to keep list integrity.

Key Takeaways

A doubly linked list node stores links to both next and previous nodes.
Always update both next and prev pointers when adding or removing nodes.
Keep track of head and tail to allow efficient insertion and deletion.
Handle empty list and single-node list cases carefully.
Test traversal forward and backward to verify list integrity.