Insert a node at the front of the linked list

AS
Ackshaey Singh
Difficulty Easy
Time Complexity
O(1)
Space Complexity
O(1)
Linked list
Firecode

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 next is 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

  1. Empty list (null head): The new node becomes the only element. Its next is null.
  2. Single-node list: The new node points to the existing single node.
  3. 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:

  1. Create a new node with the given value
  2. Link the new node's next pointer to the current head
  3. 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 next pointer: 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

OperationTimeWhy
Insert at frontO(1)Direct pointer manipulation
Insert at endO(n)Must traverse to find the tail
Insert at index kO(k)Must traverse k nodes
Array insert at index 0O(n)Must shift all elements right

This is precisely why linked lists excel at front insertion. It is their superpower.

Common Pitfalls

  1. Returning the old head instead of the new node: The most frequent mistake. After insertion, the new node is the head, not the original head parameter.

    // Wrong - returns the old head, losing the new node
    return head;
    // Correct
    return newNode;
    
  2. 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;
    
  3. 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

  1. 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."

  2. Mention the edge case without over-engineering it: "This handles null head naturally because setting next to null is valid."

  3. Draw it out: Sketch two boxes with arrows. Interviewers love visual thinkers, even for simple problems.

  4. 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)
  5. 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 = null works 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;
}

Frequently Asked Questions

What is the time complexity of inserting a node at the front of a linked list?
The time complexity is O(1) because the operation involves creating a new node, pointing it to the current head, and returning the new node. No traversal of the list is required regardless of the list size.
What is the difference between inserting at the front versus the end of a linked list?
Inserting at the front is O(1) because you only manipulate the head pointer. Inserting at the end requires traversing the entire list to find the tail, making it O(n) unless you maintain a separate tail pointer.
How do you handle inserting into an empty linked list?
When the head is null, create a new node with the given value. Since there is no existing list to link to, the new node's next pointer is naturally null. Return the new node as the head of the now single-element list.
Why is linked list prepend preferred over array insertion at index 0?
Linked list prepend is O(1) because it only adjusts pointers. Array insertion at index 0 is O(n) because every existing element must be shifted one position to the right to make room for the new element.
What happens if you forget to set the new node's next pointer before returning?
If you skip setting newNode.next = head, the new node will point to null instead of the existing list. You will return a single disconnected node and lose the reference to all original list elements.
Can you insert at the front of a linked list without creating a new node?
No. Inserting at the front always requires allocating a new ListNode to hold the new data value. The operation is about adding an element, which inherently requires new memory. The O(1) space complexity refers to auxiliary space beyond the node itself.
How does front insertion relate to implementing a stack with a linked list?
Front insertion is exactly the push operation for a stack implemented as a linked list. The head of the list acts as the top of the stack. Push prepends a node in O(1) time, and pop removes the head node in O(1) time, giving you a complete stack with constant-time operations.
What are common mistakes when inserting at the front of a linked list?
The most common mistakes are forgetting to link the new node to the existing head (losing the rest of the list), returning the old head instead of the new node, and not handling the null head edge case. Always set newNode.next = head before returning newNode.