Singly Linked List: Beginner to Expert 🚀

A complete guide to singly linked lists: theory, memory model, JavaScript implementation explained simply, complexity, interview patterns and expert tips.

12 min read
beginner-to-expert#linked-list#data-structures#javascript#interview-prep

Definition and Purpose

A Singly Linked List (SLL) is like a train of nodes, where each node carries a value and a link to the next node.

  • Data — what the node carries
  • Next pointer — a chain/link to the next node

Unlike arrays, linked list nodes don't sit next to each other in memory. They are scattered, but each one knows who comes after it.

Purpose

  • Fast insertions and deletions anywhere in the list
  • Dynamic memory — we don't need to know the size ahead of time
  • Base structure for stacks, queues, LRU cache and more

Core Theory & Mechanics

  • Head — first node of the list
  • Tail — last node (next = null)
  • Traversal — start at head, follow next pointers until the end

Memory Insight

Each node is an object in memory. The next pointer stores the address of the next node. This is not cache-friendly like arrays, because nodes are scattered across memory.

JavaScript Example — Explained Simply

Step 1: Node Class

node.js
class Node {
  constructor(data) {
    this.data = data; // store the value
    this.next = null; // start with no next node
  }
}

Kid-friendly explanation

Imagine each node is a box. data is what's inside the box, next is an arrow pointing to the next box. Initially the box has no arrow (next = null) because it's alone.

Step 2: Print the Linked List

printLinkedList.js
function printLinkedList(head) {
  if (!head) {
    console.log("Linked List not implemented");
    return;
  }

  let pointer = head; // start at the first node

  while (pointer != null) {
    console.log(pointer.data); // show the box content
    pointer = pointer.next;    // follow the arrow to the next box
  }
}
  • if (!head) — if the list is empty, show a message
  • pointer = head — we start at the first box, but we keep head safe
  • while (pointer != null) — keep going until the last box
  • pointer = pointer.next — follow the arrow to the next box

Why we use a pointer

We don't want to lose the head. Head is like the front door of our linked list house. If we move head, we forget where the list starts.

Step 3: Create Head and Add Nodes

build.js
const head = new Node(23); // first box
let pointer = head;        // start building from here

for (let k = 0; k <= 10; k++) {
  pointer.next = new Node(k); // add a new box after current
  pointer = pointer.next;     // move pointer to the new box
}

printLinkedList(head);
  • const head = new Node(23) — first box, always remember where it is
  • let pointer = head — temporary helper to add boxes without losing the head
  • pointer.next = new Node(k) — create a new box and link it after the current one
  • pointer = pointer.next — move pointer to the new box
  • The loop runs 11 times (0 to 10), so we build boxes one by one
  • printLinkedList(head) — follow arrows from the first box and print the numbers
head → [23] → [0] → [1] → [2] → ... → [10] → null
Visual representation

Key takeaways from this example

Always keep track of the head, otherwise you lose the list. Use a temporary pointer for adding nodes. Each loop iteration creates a new node and links it after the current node.

Time and Space Complexity

OperationComplexityNotes
Access by indexO(n)Must traverse from head
Search by valueO(n)Linear search
Insert at headO(1)Constant time
Insert at tailO(n)O(1) if a tail pointer is maintained
Delete headO(1)Constant time
Delete tailO(n)Must traverse to the second-last node
SpaceO(n)Each node stores data plus a pointer

Comparison Table

FeatureSingly Linked ListArray
MemoryDynamic + pointer overheadContiguous
Access by indexO(n)O(1)
Insert / delete at headO(1)O(n)
Insert / delete at tailO(n), or O(1) with tail pointerO(1) amortized
Cache friendlinessLowHigh

Mental Models

  • Train analogy — each node is a carriage, the arrow is the chain to the next carriage
  • Boxes analogy — each node is a box with data inside and an arrow pointing to the next box

Common Mistakes

  • Forgetting the head — you lose the whole list
  • Forgetting the null check — the code crashes
  • Off-by-one errors in loops — wrong node connections

Best Practices

  • Keep head safe, use a separate pointer for traversal
  • Consider a dummy node to simplify insert and delete logic
  • Maintain a tail pointer for O(1) tail insertion
  • Wrap the list in a class for a clean API

Anti-Patterns

  • Using array-style tricks on a linked list
  • Recursive traversal for long lists — risk of stack overflow
  • Traversing the list multiple times when one pass would do

Real-World Relevance

  • Frontend (React) — Virtual DOM diffing uses a similar linked structure
  • Backend (Node.js) — middleware chains and task queues
  • DSA & System Design — LRU caches, queues, adjacency lists

Advanced Topics

  • Doubly Linked List
  • Circular Linked List
  • Skip List
  • Linked List + HashMap for an LRU cache
  • XOR Linked List

Interview Insights

Common coding questions

  • Reverse a linked list
  • Detect a cycle
  • Merge two sorted linked lists
  • Find the middle node
  • Remove the Nth node from the end

Tricky follow-ups

  • Recursive vs iterative approach
  • Empty list and single-node edge cases

Expert Tips

  • Draw the list while coding in interviews
  • Always preserve the head
  • Practice patterns like reversing sublists, rotations and cycle detection
  • Understand memory, cache behaviour and pointers for real-world systems

Lokesh Choudhary

Associate Software Developer

Building scalable web and mobile applications with a focus on performance, architecture, and premium user experiences.

Available for new opportunities

Contact

© 2026 Lokesh Choudhary. All rights reserved.

Built with Next.js & Framer Motion