Linear structures and hashing · 09 / 53
Singly, doubly and circular linked lists
Understand → trace → implement → justify
2 min reading · allow extra time for practiceLinked nodes hold values and links. Singly linked lists have next; doubly linked lists add prev. A circular list ends by revisiting its start rather than encountering None. Sentinel nodes simplify boundaries but are not user data.
Insertion after a known node changes two links. Deleting a singly linked node generally requires its predecessor; knowing only the target is not always sufficient. Doubly linked deletion is O(1) when neighbours are known. Head and tail consistency belong to every operation's invariant.
Memory overhead includes pointers, allocation metadata and fragmentation; locality often loses to arrays. Floyd's two-speed traversal detects cycles. When reversing links, save the old next before overwriting it or the rest of the chain is lost.
A worked trace
Reversing A→B→C starts with prev=None, cur=A and saved nxt=B. Set A.next=None, advance prev and cur. The reversed prefix and untouched suffix remain valid.
Cost and assumptions
Search/index Θ(n); relinking known neighbours O(1); reverse Θ(n) time and O(1) auxiliary space.
Executable example
Run with Python 3. Assertions check a small example; they do not constitute a general correctness proof. Some advanced examples are explicitly small models or reference oracles, not full production implementations.
class Node:
def __init__(self, value, next=None):
self.value, self.next = value, next
def reverse(head):
prev = None
while head is not None:
nxt = head.next
head.next = prev
prev, head = head, nxt
return prev
head = reverse(Node(1, Node(2, Node(3))))
assert (head.value, head.next.value) == (3, 2)TEST YOUR UNDERSTANDING
Your turn
Why is while node is not None wrong for a circular list?
Reveal the reasoning
Links never reach None, so traversal never terminates. Compare node identity with the starting node or traverse a known count.
Take it further
- Write down the input contract and the invariant before changing the example.
- Add empty, boundary, duplicate and adversarial cases where they are relevant. Compare with a simple oracle.
- Derive the cost under the stated model; measure several input sizes and explain discrepancies.
Primary reading & lecture notes
Original explanations in this course; these references provide proofs and further reading. Source links may cover the broader module.
Pat Morin · Open Data Structures ↗