Category: Sequence types
Topics: pointer manipulation, LRU caches, browser history, undo/redo systems
A linear data structure where each node contains data and two pointers - one to the next node and one to the previous node - enabling bidirectional traversal.
| Operation | Time Complexity | Description |
|---|---|---|
| Access | O(n) | Traverse from head or tail |
| Search | O(n) | Linear scan in either direction |
| Insert (head) | O(1) | Update head and its neighbor |
| Insert (tail) | O(1) | Update tail and its neighbor |
| Insert (at node) | O(1) | Update prev/next pointers |
| Delete (head) | O(1) | Update head pointer |
| Delete (tail) | O(1) | Update tail pointer |
| Delete (at node) | O(1) | Update neighbor pointers |
class Node:
def __init__(self, data):
self.data = data
self.prev = None
self.next = None
class DoublyLinkedList:
def __init__(self):
self.head = None
self.tail = None
def append(self, data):
"""Insert at tail - O(1)"""
new_node = Node(data)
if not self.head:
self.head = self.tail = new_node
return
new_node.prev = self.tail
self.tail.next = new_node
self.tail = new_node
def prepend(self, data):
"""Insert at head - O(1)"""
new_node = Node(data)
if not self.head:
self.head = self.tail = new_node
return
new_node.next = self.head
self.head.prev = new_node
self.head = new_node
def delete(self, node):
"""Delete given node - O(1)"""
if node.prev:
node.prev.next = node.next
else:
self.head = node.next
if node.next:
node.next.prev = node.prev
else:
self.tail = node.prev
def traverse_forward(self):
"""Traverse head to tail"""
current = self.head
while current:
yield current.data
current = current.next
def traverse_backward(self):
"""Traverse tail to head"""
current = self.tail
while current:
yield current.data
current = current.prev
O(n) for n elements. Each node requires extra space for two pointers (prev and next), typically 16 bytes on 64-bit systems. No auxiliary space for operations.
Pros:
Cons: