Insert a Node in a Linked List
Table of Contents + −
So you have a linked list and you want to add a new value into it. You might add it at the front. You might add it at the end. Or you might add it somewhere in the middle. That is what inserting a node means. In this tutorial we will add a node in all three spots. After each one we will watch how the list changes.
Here is the pain. In an array, if you want to put something in the middle, you have to shift every element after it to make room. That takes time, especially in a big array. A linked list fixes this. A linked list is a chain of small boxes called nodes. Each node holds a value and a pointer to the next node. To insert, you just change a couple of pointers. Nothing gets shifted.
📚 What Is a Node?
Before we insert anything, let us be clear on what a node is.
A node is one box in the chain. It holds two things:
- the data (the value you want to store)
- the next pointer (the address of the node that comes after it)
The list itself is just a pointer to the first node. We call that first node the head. If head points to nothing, the list is empty.
So inserting a node always comes down to the same idea. Create a new node. Then fix the next pointers so the new node sits in the right place.
Before: head -> [10] -> [20] -> [30] -> NULL
Insert 99 at the front:
After: head -> [99] -> [10] -> [20] -> [30] -> NULL🎯 The Three Cases
There are three common spots where you might want to add a node.
- At the head — the new node becomes the first one in the list.
- At the tail — the new node goes to the very end.
- At a given position — the new node lands at some index you choose, like position 2.
Let us take them one at a time.
⬆️ Insert at the Head
This is the fastest case. You add the new node right at the front. Nothing else has to move.
The trick is the order of the two pointer changes. First point the new node at the old head. Only then make head point to the new node. If you do it the other way round, you lose the rest of the list.
Steps to insert at the head:
- Create a new node and put your value in it.
- Set the new node’s
nextto the current head. - Move head to point at the new node.
Here is insert-at-head in all five languages. We start with the list 10 -> 20 -> 30 and add 5 at the front.
class Node: def __init__(self, data): self.data = data self.next = None
# Insert at the front; returns the new headdef insert_at_head(head, value): n = Node(value) n.next = head # new node points to old head return n # new node is the new head
def print_list(head): parts = [] while head is not None: parts.append(str(head.data)) head = head.next print(" -> ".join(parts) + " -> NULL")
# Build 10 -> 20 -> 30head = Node(10)head.next = Node(20)head.next.next = Node(30)
head = insert_at_head(head, 5) # add 5 at the frontprint_list(head)The output of the above code will be:
5 -> 10 -> 20 -> 30 -> NULLNote
Insert at the head is O(1) — constant time. You only touch one pointer. It does not matter if the list has 10 nodes or 10 million. It is the same speed.
⬇️ Insert at the Tail
Now you want the new node at the very end. But there is a catch. To reach the end you have to walk through the whole list first. There is no shortcut unless you keep a separate tail pointer.
So you start at the head and keep moving to next until you reach the last node. The last node is the one whose next is NULL. Then you attach the new node there.
One thing to watch. If the list is empty, there is no last node to attach to. In that case the new node simply becomes the head.
Steps to insert at the tail:
- Create a new node with your value.
- If the list is empty, the new node becomes the head. Stop.
- Otherwise walk from the head until you reach the last node.
- Set the last node’s
nextto the new node.
Here we take 10 -> 20 -> 30 and add 40 at the end.
class Node: def __init__(self, data): self.data = data self.next = None
# Insert at the end; returns the headdef insert_at_tail(head, value): n = Node(value) if head is None: # empty list: new node is head return n cur = head while cur.next is not None: # walk to the last node cur = cur.next cur.next = n # attach at the end return head
def print_list(head): parts = [] while head is not None: parts.append(str(head.data)) head = head.next print(" -> ".join(parts) + " -> NULL")
head = Node(10)head.next = Node(20)head.next.next = Node(30)
head = insert_at_tail(head, 40) # add 40 at the endprint_list(head)The output of the above code will be:
10 -> 20 -> 30 -> 40 -> NULLNote
Insert at the tail is O(n) when you have no tail pointer, because you walk the whole list to reach the end. If you keep a separate pointer to the last node, this drops to O(1).
🎯 Insert at a Given Position
Now the middle case. You want the new node at a specific spot, say position 2. We count positions starting from 0, so position 0 is the head.
The idea is simple. To insert at position k, you stop at the node just before it, which is position k - 1. Then you slot the new node in between.
The order of the pointer changes matters here as well. First point the new node at whatever comes next. Then point the previous node at the new node. Do it in that order so you do not lose the rest of the list.
A couple of edge cases to keep in mind:
- If the position is 0, it is just an insert at the head.
- If the position is past the end of the list, we treat it as inserting at the tail.
Steps to insert at position k:
- Create a new node with your value.
- If
kis 0, insert at the head and stop. - Walk to the node at position
k - 1. Call itprev. - Set the new node’s
nexttoprev.next. - Set
prev.nextto the new node.
Here we take 10 -> 20 -> 30 and insert 25 at position 2.
class Node: def __init__(self, data): self.data = data self.next = None
# Insert at position k (0-based); returns the headdef insert_at_position(head, value, k): n = Node(value) if k == 0: # position 0 is the head n.next = head return n prev = head i = 0 # stop at the node just before position k while i < k - 1 and prev.next is not None: prev = prev.next i += 1 n.next = prev.next # new node points to the rest prev.next = n # previous node points to new node return head
def print_list(head): parts = [] while head is not None: parts.append(str(head.data)) head = head.next print(" -> ".join(parts) + " -> NULL")
head = Node(10)head.next = Node(20)head.next.next = Node(30)
head = insert_at_position(head, 25, 2) # put 25 at position 2print_list(head)The output of the above code will be:
10 -> 20 -> 25 -> 30 -> NULLNote
Insert at a given position is O(n) in the worst case. You may have to walk almost the whole list to reach the spot just before position k.
🔁 How the Pointers Move
Here is the middle insert as a picture. See how 25 slips in between 20 and 30 by changing just two pointers.
The node 20 used to point at 30. Now it points at our new node 25, and 25 points at 30. The two ends of the chain are joined again with the new node in the middle. Nothing else moved.
Tip
Always set the new node’s next first, then change the previous node’s next. If you flip the order, you lose the address of the rest of the list and the nodes after the insert point are gone.
⏱️ Time and Space Complexity
Here is the cost of each case side by side.
| Operation | Time | Space | Why |
|---|---|---|---|
| Insert at head | O(1) | O(1) | Just change one pointer at the front. |
| Insert at tail (no tail pointer) | O(n) | O(1) | Walk the whole list to reach the end. |
| Insert at tail (with tail pointer) | O(1) | O(1) | Jump straight to the last node. |
| Insert at position k | O(n) | O(1) | Walk up to position k minus 1. |
Notice the space is always O(1). We add one new node no matter what. We never copy or shift the existing list like an array would.
⚠️ Common Mistakes
A few traps that catch almost everyone the first time:
- Changing the previous pointer first. Always link the new node to the rest before you re-point the previous node. Otherwise the tail of the list is lost.
- Forgetting the empty list case. When head is
NULL, the new node becomes the head. If you skip this check, your tail and position code crashes. - Walking one step too far. For a position insert you stop at position
k - 1, notk. Going one extra step puts the node in the wrong spot. - Forgetting to return or save the new head. When you insert at the head, the head changes. If the caller does not save the returned head, it still points at the old front.
🧩 What You’ve Learned
✅ A node holds data plus a next pointer, and the list is just a pointer to the head.
✅ Insert at the head is O(1) — point the new node at the old head, then move head.
✅ Insert at the tail is O(n) without a tail pointer, because you walk to the end first.
✅ Insert at a position means stopping at position k - 1, then slotting the node in with two pointer changes — also O(n).
✅ Always set the new node’s next before changing the previous node’s next, or you lose the rest of the list.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
Why is inserting at the head of a singly linked list O(1)?
Why: Insert at head touches just one or two pointers at the front, so the size of the list does not matter.
- 2
Without a tail pointer, what is the time cost of inserting at the end of a linked list?
Why: You must walk from the head all the way to the last node, so it takes O(n) time.
- 3
When inserting a new node in the middle, which pointer should you set first?
Why: Set the new node's next first so you keep the address of the rest of the list before re-pointing the previous node.
- 4
To insert at position k (0-based), which node do you stop at before linking?
Why: You stop at position k minus 1 so the new node can be slotted right before position k.