Overview
A doubly linked list is a linear data structure where each node contains pointers to both the next and previous nodes, enabling bidirectional traversal. This provides more flexibility than singly linked lists at the cost of extra memory for the additional pointer.Data Structure Definition
The doubly linked list node is defined inlists.h:15-20:
lists.h
Each node contains:
n: The integer valueprev: Pointer to the previous node (NULL for head)next: Pointer to the next node (NULL for tail)
Basic Operations
Traversal and Printing
print_dlistint.c
Space Complexity: O(1) - only counter variable
Insertion Operations
Insert at Beginning
add_dnodeint.c
Insert at End
add_dnodeint_end.c
Key differences from singly linked list:
- After finding the tail, we must set
new->prev = hto link backward - The tail can now traverse backward to reach any previous node
- Setting
new->prev = hworks even whenhis NULL (empty list case)
Advanced Operations
Insert at Index
insert_dnodeint_at_index.c
Delete at Index
delete_dnodeint_at_index.c
Deletion requires updating both directions:Case 1: Delete head (index 0)Case 2: Delete middle/end nodeAlways check if
next exists before updating its prev pointer!Complete Function Set
Fromlists.h:22-30, the full API includes:
lists.h
Usage Example
example.c
Complexity Summary
| Operation | Time | Space | Notes |
|---|---|---|---|
| Insert at head | O(1) | O(1) | Direct access |
| Insert at tail | O(n) | O(1) | Must find tail |
| Insert at index | O(n) | O(1) | Traverse to position |
| Delete at index | O(n) | O(1) | Traverse to position |
| Search | O(n) | O(1) | Linear search |
| Traverse forward | O(n) | O(1) | Visit each node |
| Traverse backward | O(n) | O(1) | Unique to doubly linked |
Advantages Over Singly Linked Lists
- Bidirectional traversal: Can move forward and backward through the list
- Easier deletion: Given a node, can delete it without needing previous node reference
- Better for certain algorithms: Ideal for LRU caches, browser history, undo/redo functionality
- Symmetric operations: Insert and delete operations are more uniform
Trade-offs
Advantages:- Bidirectional traversal
- Easier node deletion when you have direct reference to the node
- More flexible for certain algorithms
- Extra memory for
prevpointer (approximately 50% more per node) - More pointer updates per operation (4 vs 2 for insertions)
- Slightly more complex code to maintain both directions