A doubly linked list (DLL) is a sequence of nodes where each node stores:
Because nodes link in both directions, you can traverse forward and backward and perform insertions/deletions in O(1) time when you already have a reference to the node at the insertion/deletion point.
// C-like
struct Node {
int value;
Node* prev;
Node* next;
};
struct List {
Node* head;
Node* tail;
size_t size;
};
Maintaining head and tail pointers allows O(1) insertion/removal at both ends.
function push_front(list, x):
n = new Node(x)
n.prev = null
n.next = list.head
if list.head != null:
list.head.prev = n
else:
list.tail = n // list was empty
list.head = n
list.size++
function insert_after(node, x, list):
n = new Node(x)
n.prev = node
n.next = node.next
if node.next != null:
node.next.prev = n
else:
list.tail = n
node.next = n
list.size++
function erase(node, list):
if node.prev != null:
node.prev.next = node.next
else:
list.head = node.next
if node.next != null:
node.next.prev = node.prev
else:
list.tail = node.prev
free(node)
list.size--
tail.next = head and head.prev = tail simplify some edge cases.prev and next links during insert/delete.std::list for safety. Be mindful of allocator overhead and iterator invalidation rules.LinkedList<T> is typically a doubly linked list; garbage collection handles reclamation.collections.deque is a high-performance double-ended queue (not a pure DLL implementation but similar use cases). A custom DLL can be built with classes.function traverse_backward(list):
cur = list.tail
while cur != null:
visit(cur.value)
cur = cur.prev
prev/next pairs, accurate size.Choose a doubly linked list when you need frequent insertions/deletions at arbitrary positions with node references, bidirectional traversal, or list reordering (move-to-front) — and you can tolerate extra pointer memory and reduced cache locality compared to arrays.