Skillversitas

Doubly Linked List

A Doubly Linked List has next and prev pointers in every node. This allows traversal in both directions: forward and backward.

Node Implementation

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None
        self.prev = None

Doubly Linked List Implementation

class DoublyLinkedList:
    def __init__(self):
        self.head = None

    def insert_head(self, data):
        new_node = Node(data)
        new_node.next = self.head
        if self.head:
            self.head.prev = new_node
        self.head = new_node

    def insert_tail(self, data):
        new_node = Node(data)
        if not self.head:
            self.head = new_node
            return
        curr = self.head
        while curr.next:
            curr = curr.next
        curr.next = new_node
        new_node.prev = curr

    def delete(self, data):
        curr = self.head
        while curr:
            if curr.data == data:
                if curr.prev:
                    curr.prev.next = curr.next
                else:
                    self.head = curr.next
                if curr.next:
                    curr.next.prev = curr.prev
                return
            curr = curr.next

    def traverse_forward(self):
        result = []
        curr = self.head
        while curr:
            result.append(curr.data)
            curr = curr.next
        return result

    def traverse_backward(self):
        result = []
        curr = self.head
        if not curr:
            return result
        while curr.next:
            curr = curr.next
        while curr:
            result.append(curr.data)
            curr = curr.prev
        return result

Singly vs Doubly Linked List

Aspect Singly Doubly
Pointers per node 1 (next) 2 (next + prev)
Memory per node More economical More
Traversal One direction Two directions
Delete node Needs the prev pointer Direct via prev
Insert before O(n) to find prev O(1) if you hold a reference

Time Complexity

Operation Time
Insert head O(1)
Insert tail O(n) without a tail pointer
Delete O(1) if you hold a reference to the node
Search O(n)

Use Cases

  • LRU Cache: Fast access from both ends.
  • Browser history: Back and forward.
  • Music player: Next and previous.
  • Text editor: Undo/redo.
dll = DoublyLinkedList()
dll.insert_tail(10)
dll.insert_tail(20)
dll.insert_head(5)
print(dll.traverse_forward())   # [5, 10, 20]
print(dll.traverse_backward())  # [20, 10, 5]
dll.delete(10)
print(dll.traverse_forward())   # [5, 20]

A Doubly Linked List makes two-way operations easy. Now let's study the Stack, which limits access to a single end.