After this lesson, you will be able to: Implement singly, doubly, and circular linked lists from scratch, and know exactly when a linked list beats an array and when it does not.
A linked list trades the array's fast random access for fast insertion and deletion. Understanding that single tradeoff tells you everything about when to reach for one.
Instead of one contiguous block, a linked list is a chain of nodes scattered anywhere in memory. Each node holds a value and a pointer to the next node. To find the 5th element you must start at the head and follow 5 pointers. There is no address math, so access is O(n). But to insert a new node, you just rewire two pointers, which is O(1) once you are at the spot.
Implement it by hand. This is a classic interview ask.
class Node:def __init__(self, value):self.value = valueself.next = Noneclass LinkedList:def __init__(self):self.head = Noneself.size = 0def prepend(self, value): # O(1): new headnode = Node(value)node.next = self.headself.head = nodeself.size += 1def find(self, value): # O(n): must walk the chaincurrent = self.headwhile current:if current.value == value:return currentcurrent = current.nextreturn Nonedef to_list(self):out, current = [], self.headwhile current:out.append(current.value)current = current.nextreturn out
A singly linked list has next pointers only, so you can move forward but not back. A doubly linked list adds a prev pointer in each node, so you can walk both directions and delete a node in O(1) if you already have a reference to it. A circular linked list points the last node back to the first, useful for round-robin scheduling and buffers that wrap. Doubly linked lists power things like browser history and LRU caches.
The single most common linked-list interview question. Do it before looking at any solution.
1. Keep three pointers: prev (start None), current (start head), and next.
2. In a loop: save next = current.next, point current.next back to prev.
3. Advance: prev = current, current = next.
4. When current is None, prev is the new head.
5. Test it on [1,2,3,4] and confirm you get [4,3,2,1].
Losing the rest of the list by reassigning current.next before saving the next node (always save next first). Forgetting to update the tail pointer when you maintain one. Off-by-one errors at the head and tail (the boundaries are where linked-list bugs live). Reaching for a linked list in production for performance when an array would be faster due to cache locality. Creating a cycle by accident and then looping forever (use Floyd's tortoise-and-hare to detect cycles).
Sign in and purchase access to unlock this lesson.