Linked Lists
Singly Linked List
Build a singly linked list from scratch and learn how to insert, delete, and traverse it.
Singly Linked List
A singly linked list is the simplest form. Each node has a value and one pointer — next — pointing to the next node. You can only move forward through the list.
Singly Linked Liststep-through
head
val
10
next
→
val
20
next
→
val
30
next
→
val
40
next
→
val
50
next
None
singly_linked.py
def prepend(value):
new_node = Node(value)
new_node.next = self.head
self.head = new_node
prepend(5) — add to beginning
step 0/3
0%
Full implementation
class Node:
def __init__(self, value):
self.value = value
self.next = None
class SinglyLinkedList:
def __init__(self):
self.head = None
self.size = 0
def append(self, value):
"""Add to the end — O(n)"""
new_node = Node(value)
if not self.head:
self.head = new_node
else:
current = self.head
while current.next:
current = current.next
current.next = new_node
self.size += 1
def prepend(self, value):
"""Add to the beginning — O(1)"""
new_node = Node(value)
new_node.next = self.head
self.head = new_node
self.size += 1
def insert_at(self, index, value):
"""Insert at a specific index — O(n)"""
if index == 0:
self.prepend(value)
return
new_node = Node(value)
current = self.head
for _ in range(index - 1):
if not current:
raise IndexError("Index out of range")
current = current.next
new_node.next = current.next
current.next = new_node
self.size += 1
def delete_head(self):
"""Remove from beginning — O(1)"""
if not self.head:
return None
value = self.head.value
self.head = self.head.next
self.size -= 1
return value
def delete_at(self, index):
"""Remove at a specific index — O(n)"""
if index == 0:
return self.delete_head()
current = self.head
for _ in range(index - 1):
if not current.next:
raise IndexError("Index out of range")
current = current.next
value = current.next.value
current.next = current.next.next
self.size -= 1
return value
def search(self, value):
"""Find index of value — O(n)"""
current = self.head
index = 0
while current:
if current.value == value:
return index
current = current.next
index += 1
return -1
def to_list(self):
result = []
current = self.head
while current:
result.append(current.value)
current = current.next
return resultHow insert at beginning works — O(1)
Before: head → [10] → [20] → [30] → None
Step 1 — create new node:
new → [5] → None
Step 2 — new.next = head:
new → [5] → [10] → [20] → [30] → None
Step 3 — head = new:
head → [5] → [10] → [20] → [30] → NoneJust two pointer reassignments. No elements move. O(1).
How delete at position works — O(n)
Delete index 2 from: [10] → [20] → [30] → [40] → None
Step 1 — walk to node before target (index 1):
current = [20]
Step 2 — bypass the target:
current.next = current.next.next
Result: [10] → [20] → [40] → None
[30] is now unreachable — garbage collectedReversing a linked list
A classic interview problem:
def reverse(self):
prev = None
current = self.head
while current:
next_node = current.next # save next
current.next = prev # reverse pointer
prev = current # move prev forward
current = next_node # move current forward
self.head = prevThe reversal uses three pointers — prev, current, and next_node. At each step, reverse the current pointer, then advance both prev and current. When current becomes None, prev is the new head.
Complexity
| Operation | Time | Space |
|---|---|---|
| Prepend | O(1) | O(1) |
| Append | O(n) | O(1) |
| Insert at index | O(n) | O(1) |
| Delete head | O(1) | O(1) |
| Delete at index | O(n) | O(1) |
| Search | O(n) | O(1) |
| Traverse | O(n) | O(1) |