Insert a node at the front of the linked list
You are fifteen minutes into your first technical screen and the interviewer says, "Let's start with something quick. Given a linked list, insert a new node at the front." It sounds trivial, but this tiny operation is the building block for stacks, undo systems, and more complex linked list problems. Getting it right under pressure, handling the null case cleanly, returning the correct node, shows an interviewer that you truly understand how pointers work. This problem, sometimes called "Linked List Prepend" on other platforms, is one of the first linked list operations every candidate should master.
TL;DR
Create a new ListNode with the given value, point its next to the current head, and return the new node as the new head. This runs in O(1) time and O(1) space because no traversal is needed. The same logic handles both empty and non-empty lists since setting newNode.next = null (when head is null) is perfectly valid.
Why This Problem Matters
Inserting at the front of a linked list is the simplest linked list mutation, but it tests two things interviewers care about: pointer manipulation and edge case awareness. If you can't prepend a node correctly, you'll struggle with reversal, merging, and cycle detection down the road. Think of this as the "Hello World" of linked list operations. Nail it, and you build confidence for everything that follows.
Linked Lists: A Quick Refresher
A singly linked list is a chain of nodes where each node holds a value and a reference to the next node. The last node points to null, signaling the end of the chain.
Loading visualization...
Key properties:
- Head: The first node in the list, your only entry point
- Next pointer: Each node stores a reference to the following node
- Null terminator: The last node's
nextis null - No random access: You must walk the chain from the head to reach any node
Unlike arrays, linked lists do not store elements in contiguous memory. This means inserting or removing at the front is cheap (no shifting), but finding the kth element requires traversal.
Understanding the Problem
Given: The head node of a singly linked list and an integer n
Task: Insert a new node with value n at the front of the list
Return: The new head of the modified list
Here is the example from the problem description. Starting with the list [1, 2]:
Loading visualization...
After calling insertAtFront(head, 3), the list becomes [3, 1, 2]:
Loading visualization...
The new node with value 3 is now the head, and it points to the old head (node 1).
Edge Cases to Consider
- Empty list (null head): The new node becomes the only element. Its
nextis null. - Single-node list: The new node points to the existing single node.
- Large list: The operation should still be O(1), no matter the list length.
For the empty list case, inserting value 5 into null produces:
Loading visualization...
Solution Approach
This problem requires exactly three steps, and the order matters:
- Create a new node with the given value
- Link the new node's
nextpointer to the current head - Return the new node (it is now the head)
The critical insight is that step 2 works regardless of whether head is null or not. If the list is empty, newNode.next = null is fine. If the list has elements, newNode.next = head chains the new node to the existing list. No special case needed.
Walking Through the Steps
Let's trace through inserting 3 at the front of [1, 2].
Step 1: Create a new node with value 3.
Loading visualization...
Step 2 and 3: Set newNode.next = head and return the new node. The highlighted node is our new head:
Loading visualization...
That is the entire algorithm. Three lines of code.
Implementation
Prefer a different language? Jump to solutions in other languages.
public class Solution {
public ListNode insertAtFront(ListNode head, int n) {
// Create a new node with the given value
ListNode newNode = new ListNode(n);
// Point the new node to the current head
newNode.next = head;
// The new node is now the head of the list
return newNode;
}
}
Let's verify with a longer example. Inserting 6 at the front of [1, 2, 3, 4, 5]:
Loading visualization...
After insertAtFront(head, 6):
Loading visualization...
The highlighted node (6) is the new head. The rest of the list is completely untouched.
Complexity Analysis
Time Complexity: O(1)
Every operation is constant time:
- Creating a node: O(1)
- Setting the
nextpointer: O(1) - Returning: O(1)
No loops, no traversal, no recursion. The list could have five nodes or five million and the time is identical.
Space Complexity: O(1)
We allocate exactly one new node (which is inherent to the problem, not auxiliary overhead) and use no additional data structures. The space used does not grow with the size of the input list.
Comparison with Other Insert Positions
| Operation | Time | Why |
|---|---|---|
| Insert at front | O(1) | Direct pointer manipulation |
| Insert at end | O(n) | Must traverse to find the tail |
| Insert at index k | O(k) | Must traverse k nodes |
| Array insert at index 0 | O(n) | Must shift all elements right |
This is precisely why linked lists excel at front insertion. It is their superpower.
Common Pitfalls
-
Returning the old head instead of the new node: The most frequent mistake. After insertion, the new node is the head, not the original
headparameter.// Wrong - returns the old head, losing the new node return head; // Correct return newNode; -
Forgetting to link the new node to the existing list: If you skip
newNode.next = head, you return a disconnected single node and the rest of the list is lost.// Wrong - newNode.next defaults to null, entire list is lost ListNode newNode = new ListNode(n); return newNode; -
Adding unnecessary null checks: Some candidates write separate logic for the empty list case. It is not needed. Setting
newNode.next = null(when head is null) works perfectly.
Interview Tips
-
Start by stating the approach: "I'll create a new node, point it to the current head, and return it. This is O(1) time and space."
-
Mention the edge case without over-engineering it: "This handles null head naturally because setting next to null is valid."
-
Draw it out: Sketch two boxes with arrows. Interviewers love visual thinkers, even for simple problems.
-
Prepare for follow-ups:
- "How would you insert at the end?" (Traverse to tail, O(n))
- "How would you insert at a specific position?" (Traverse to position k-1, O(k))
- "How does this relate to stacks?" (Front insert = push, front remove = pop)
-
Connect to bigger concepts: Mention that prepend is the core operation behind stack implementations, undo history, and the building block for list reversal.
Real-World Applications
Front insertion is everywhere, even if you do not always see it:
- Stack implementation: Push onto a linked-list-backed stack is exactly front insertion. Pop removes the head. Both are O(1).
- Undo/redo systems: Each new action is prepended to a history list. Undo pops from the front.
- Memory allocators: Free lists in memory management systems prepend freed blocks at the front for O(1) deallocation.
- Event sourcing: New events prepended to an event log for most-recent-first access.
Key Takeaways
- Front insertion is a three-step operation: create node, set next to head, return the new node. Memorize this sequence.
- The operation is O(1) time and O(1) space because it never traverses the list, regardless of size.
- No special handling is needed for empty lists. Setting
newNode.next = nullworks naturally. - Always return the new node, not the old head. This is the most common bug candidates introduce.
- Front insertion is the foundation for stacks, undo systems, and more complex linked list algorithms like reversal and merge.
Practice and Next Steps
Once you have this down cold, move on to these related problems to build out your linked list skills:
- Insert a node at the end of a linked list (requires traversal)
- Delete a node from a linked list
- Reverse a linked list (uses the same pointer manipulation instinct)
- Find the middle of a linked list
This problem and hundreds of other linked list challenges are available on Firecode, where over 50,000 engineers have prepared for technical interviews. Whether you are just starting your data structures journey or polishing up before an on-site, consistent practice on fundamentals like this makes all the difference.
Solutions in Other Languages
Python
class Solution:
def insert_at_front(self, head: ListNode, n: int) -> ListNode:
new_node = ListNode(n)
new_node.next = head
return new_node
JavaScript
class Solution {
insertAtFront(head, n) {
const newNode = new ListNode(n);
newNode.next = head;
return newNode;
}
}
TypeScript
class Solution {
insertAtFront(head: ListNode | null, n: number): ListNode {
const newNode = new ListNode(n);
newNode.next = head;
return newNode;
}
}
C++
class Solution {
public:
ListNode *insertAtFront(ListNode *head, int n) {
auto *newNode = new ListNode(n);
newNode->next = head;
return newNode;
}
};
Go
func (s *Solution) InsertAtFront(head *ListNode, n int) *ListNode {
newNode := &ListNode{Data: n, Next: nil}
newNode.Next = head
return newNode
}
Scala
class Solution {
def insertAtFront(head: ListNode, n: Int): ListNode = {
val newNode = new ListNode(n)
newNode.next = head
newNode
}
}
Kotlin
class Solution {
fun insertAtFront(head: ListNode?, n: Int): ListNode? {
val newNode = ListNode(n)
newNode.next = head
return newNode
}
}
Rust
pub fn insert_at_front(&self, head: Option<Box<ListNode>>, n: i32) -> Option<Box<ListNode>> {
let new_node = ListNode::with_next(n, head);
Some(Box::new(new_node))
}
Rust's ownership model means the old head is moved into the new node. No manual pointer wiring needed since ListNode::with_next handles it in the constructor.
Swift
func insertAtFront(_ head: ListNode?, _ n: Int) -> ListNode? {
let newNode = ListNode(n)
newNode.next = head
return newNode
}
Ruby
def insert_at_front(head, n)
new_node = ListNode.new(n)
new_node.next = head
new_node
end
Dart
ListNode? insertAtFront(ListNode? head, int n) {
ListNode newNode = ListNode(n);
newNode.next = head;
return newNode;
}
C#
public ListNode? insertAtFront(ListNode? head, int n) {
var newNode = new ListNode(n);
newNode.next = head;
return newNode;
}
PHP
public function insertAtFront(?ListNode $head, int $n): ?ListNode {
$newNode = new ListNode($n);
$newNode->next = $head;
return $newNode;
}