arrow_backBack

How to Code a Linked List in Python

Just a Node class, a LinkedList class, and the actual understanding of what your pointers are doing. Plus an interactive visualizer so you can see it happen.

calendar_todayMarch 202612 min read
Practice linked list problemsarrow_forward
Linked list in Python visualization

Python doesn't have a built-in linked list. That's actually a good thing, because building one yourself is the fastest way to understand how pointers work, how memory allocation differs from arrays, and why interviewers love asking about them.

We're going to build a singly linked list from scratch. No hand-waving. Every method explained, every edge case covered. And there's an interactive visualizer halfway through so you can actually see what the code does.

What Even Is a Linked List

A linked list is a chain of nodes. Each node holds two things: a value, and a reference to the next node. The last node points to None. That's it.

Unlike a Python list (which is really an array under the hood), a linked list doesn't store elements next to each other in memory. Each node can live anywhere. They're connected only by the .next pointers.

This means inserting at the head is O(1), you just create a node and point it to the old head. But accessing the 5th element is O(n), you have to walk through nodes 1, 2, 3, 4 to get there.

The Node Class

Every linked list starts here. A node is dead simple:

Python
1class Node:
2 def __init__(self, data):
3 self.data = data
4 self.next = None # pointer to next node

That's the entire Node class. self.data holds the value. self.next holds a reference to the next node (or None if it's the last one). Two attributes.

The LinkedList Class

The linked list itself just needs to keep track of one thing: the head node. Everything else is built from there by walking the chain.

Python
1class LinkedList:
2 def __init__(self):
3 self.head = None # empty list
4
5 def is_empty(self):
6 return self.head is None

An empty linked list is just self.head = None. No pre-allocated memory. No capacity. It grows one node at a time.

Now let's actually add some data to this thing. But first, play with the visualizer below. It'll make the next sections way easier to follow.

Try It Live

Append a few values. Then try prepend, delete, and reverse. Watch how the pointers change. This is exactly what your Python code is doing under the hood.

linkInteractive Linked List Visualizer
link

Append values to build a linked list

List contents

Empty

Append a value or build a random linked list to get started.

Append (Add to End)

Appending means adding a new node at the end of the list. You have to walk to the last node first, because we don't have a tail pointer.

Python
1def append(self, data):
2 new_node = Node(data)
3
4 if self.head is None: # empty list?
5 self.head = new_node # new node becomes head
6 return
7
8 current = self.head # start at head
9 while current.next: # walk to the end
10 current = current.next
11 current.next = new_node # link last node to new node

The key thing here: we have to check if the list is empty first. If self.head is None, the new node just becomes the head. Otherwise, we walk to the end with a while loop and attach the new node there. O(n) because of the walk.

Prepend (Add to Front)

Adding to the front is O(1) this is linked list strong suit.

Python
1def prepend(self, data):
2 new_node = Node(data)
3 new_node.next = self.head # point to old head
4 self.head = new_node # new node is now head

Two lines of actual logic. Create the node, point it to the current head, make it the new head. Done. This works even if the list is empty, because new_node.next would just be None, which is correct.

Delete by Value

Deletion is where people mess up in interviews. You need to handle three cases: deleting the head, deleting a middle node, and the value not existing.

Python
1def delete(self, data):
2 if self.head is None: # empty list
3 return
4
5 if self.head.data == data: # deleting the head?
6 self.head = self.head.next # skip it
7 return
8
9 current = self.head
10 while current.next: # walk the list
11 if current.next.data == data:
12 current.next = current.next.next # skip the node
13 return
14 current = current.next

The trick is looking one node ahead: current.next.data == data. When you find a match, you skip over that node by pointing current.next to current.next.next. The deleted node just becomes garbage collected.

Walk the list. Compare each node. Return True or False. About as straightforward as it gets.

Python
1def search(self, data):
2 current = self.head
3 while current:
4 if current.data == data:
5 return True
6 current = current.next
7 return False

O(n). No way around it. If the value is at the end, you walk the entire list. If it doesn't exist, you also walk the entire list. That's the tradeoff.

Reverse (The Interview Classic)

This is the most-asked linked list interview question. Three pointers: prev, curr, next_node. You flip each arrow one node at a time.

Python
1def reverse(self):
2 prev = None
3 curr = self.head
4
5 while curr: # until we run off the end
6 next_node = curr.next # save the next node
7 curr.next = prev # flip the arrow
8 prev = curr # advance prev
9 curr = next_node # advance curr
10
11 self.head = prev # prev is the new head

Go back to the visualizer above and hit “Reverse.” Watch the arrows flip one by one. That's exactly what this code does. prev starts as None, curr starts at head, and each iteration flips one pointer. When curr hits None, prev is pointing at what used to be the last node, which is now the first. O(n) time, O(1) space.

The Full Code

Here's everything together. Copy it, run it, break it, fix it. That's how you learn.

Python — Complete LinkedList
1class Node:
2 def __init__(self, data):
3 self.data = data
4 self.next = None
5
6
7class LinkedList:
8 def __init__(self):
9 self.head = None
10
11 def append(self, data):
12 new_node = Node(data)
13 if not self.head:
14 self.head = new_node
15 return
16 curr = self.head
17 while curr.next:
18 curr = curr.next
19 curr.next = new_node
20
21 def prepend(self, data):
22 new_node = Node(data)
23 new_node.next = self.head
24 self.head = new_node
25
26 def delete(self, data):
27 if not self.head:
28 return
29 if self.head.data == data:
30 self.head = self.head.next
31 return
32 curr = self.head
33 while curr.next:
34 if curr.next.data == data:
35 curr.next = curr.next.next
36 return
37 curr = curr.next
38
39 def search(self, data):
40 curr = self.head
41 while curr:
42 if curr.data == data:
43 return True
44 curr = curr.next
45 return False
46
47 def reverse(self):
48 prev = None
49 curr = self.head
50 while curr:
51 next_node = curr.next
52 curr.next = prev
53 prev = curr
54 curr = next_node
55 self.head = prev
56
57 def display(self):
58 nodes = []
59 curr = self.head
60 while curr:
61 nodes.append(str(curr.data))
62 curr = curr.next
63 print(" -> ".join(nodes) + " -> None")

Linked List vs Python List

“Why would I ever use this when Python has lists?” Honest answer: in Python specifically, you probably wouldn't in production code. But understanding the difference is critical for interviews.

OperationLinked ListPython listWinner
Insert at frontO(1)O(n)Linked List
Insert at endO(n)*O(1) amortizedPython list
Access by indexO(n)O(1)Python list
Delete at frontO(1)O(n)Linked List
SearchO(n)O(n)Tie
Memory per elementMore (data + pointer)Less (contiguous)Python list

*O(1) if you keep a tail pointer. We didn't in our implementation to keep it simple.

Linked List Interview Problems

You've built the data structure. Here are the problems interviewers actually ask about it:

Reverse a linked list

You just built this. The three-pointer approach. They want you to write it from memory.

Detect a cycle

Floyd's tortoise and hare. Two pointers, one moves 2x speed. If they meet, there's a cycle.

Find the middle node

Fast pointer moves 2 steps, slow moves 1. When fast hits the end, slow is at the middle.

Merge two sorted lists

Compare heads, pick the smaller one, advance that pointer. Repeat until both are empty.

Remove nth from end

Two pointers, n nodes apart. When the leader hits the end, the follower is at the target.

Check if palindrome

Find middle, reverse the second half, compare node by node.

Can you code a linked list reversal while explaining your approach?

Reading this tutorial is step one. Writing the code under time pressure while an AI interviewer asks you about edge cases is step two.

Try a free mock interviewarrow_forward

Frequently Asked Questions

Does Python have a built-in linked list?add

No. Python's built-in list is a dynamic array, not a linked list. If you need a linked list in Python, you build one yourself with classes. collections.deque is implemented as a doubly linked list under the hood, but it doesn't expose the node structure.

When should I use a linked list instead of a Python list?add

In practice, almost never. Python's list is faster for almost everything due to cache locality. Linked lists matter in interviews and in specific systems programming scenarios where you need O(1) insertion/deletion at the head without shifting elements. In Python, use deque if you need fast append/pop from both ends.

What is the time complexity of linked list operations?add

Prepend is O(1). Append is O(n) without a tail pointer, O(1) with one. Search is O(n). Delete is O(n) because you need to find the node first. Reverse is O(n) time and O(1) space.

How do I reverse a linked list in Python?add

Use three variables: prev (starts as None), curr (starts as head), and next_node. At each step, save curr.next, point curr.next to prev, then advance prev and curr. When curr is None, prev is the new head. This runs in O(n) time with O(1) extra space.

What linked list problems show up in coding interviews?add

The most common are: reverse a linked list, detect a cycle (Floyd's algorithm), find the middle node (fast/slow pointers), merge two sorted lists, remove the nth node from the end, and check if a linked list is a palindrome.