Types

Singly Linked List

Singly Linked List

A singly linked list is a chain of nodes where each node holds a value and a single pointer to the node after it. There's no fixed size to worry about — nodes are created and linked in as needed, which is what makes insertion and deletion so cheap compared to an array.

A head pointer marks where the chain starts, and the last node's pointer is simply null, marking where it ends. Adding or removing right at the head is O(1), but reaching some node in the middle means walking node-by-node from the start, which costs O(n).

It's one of the simplest data structures around, which is exactly why it shows up as the foundation for stacks, queues, and even graph adjacency lists.

Key Property: Each node contains data and a single pointer to the next node, forming a unidirectional chain.

Basic Operations

OperationTime ComplexityDescription
Insertion at HeadO(1)Add new node at beginning by updating head pointer
Insertion at TailO(n)Traverse to end and add new node (O(1) with tail pointer)
Deletion at HeadO(1)Remove first node by updating head pointer
Deletion by ValueO(n)Traverse list to find and remove specific node
SearchO(n)Traverse list to find element
Access by IndexO(n)Traverse list until reaching desired position

Implementation

class Node {
constructor(data) {
this.data = data;
this.next = null;
}
}
class SinglyLinkedList {
constructor() {
this.head = null;
this.size = 0;
}
// Check if list is empty
isEmpty() {
return this.head === null;
}
// Insert at head
insertFirst(data) {
const newNode = new Node(data);
newNode.next = this.head;
this.head = newNode;
this.size++;
}

Insertion at Head

  1. 1. Create new node with given data
  2. 2. Set new node's next to current head
  3. 3. Update head pointer to new node
  4. 4. Increment list size counter
head →
[A|•] → [B|•] → null
↓ Insert X at head ↓
head →
[X|•] → [A|•] → [B|•] → null

Deletion Operations

  1. 1. Check if list is empty (head === null)
  2. 2. If deleting head, update head to head.next
  3. 3. For middle deletion, find previous node and update its next pointer
  4. 4. Decrement list size counter
  5. 5. Return deleted data (if needed)
head →
[X|•] → [A|•] → [B|•] → null
↓ Delete A ↓
head →
[X|•] → [B|•] → null

Operation Visualization

OperationList State
Initializationhead → null
insertFirst(10)head → [10|•] → null
insertFirst(20)head → [20|•] → [10|•] → null
insertLast(30)head → [20|•] → [10|•] → [30|•] → null
deleteFirst()head → [10|•] → [30|•] → null
delete(30)head → [10|•] → null

Pros and Cons

Advantages

  • Dynamic size - grows as needed
  • Efficient insertion/deletion at head
  • No memory waste (only allocates needed nodes)

Limitations

  • No random access - must traverse from head
  • Extra memory for next pointers
  • Not cache-friendly (nodes scattered in memory)

Applications

  • Implementing stacks and queues
  • Memory management systems
  • Undo functionality in software
  • Hash table collision handling
  • Polynomial representation and arithmetic
  • Browser history navigation

Note: Singly linked lists are preferred when you need constant-time insertions/deletions at the beginning and don't require backward traversal.

Advertisement

Visualize Singly Linked List Operations

Linked List Memory Representation

No nodes in the list yet. Add your first node!

Test Your Knowledge before moving forward!

Linked List Quiz Challenge

How it works:

  • +1 point for each correct answer
  • 0 points for wrong answers
  • -0.5 point penalty for viewing explanations
  • Earn stars based on your final score (max 5 stars)

Singly Linked List Implementation

// Singly Linked List Implementation in JavaScript
class Node {
  constructor(data) {
    this.data = data;
    this.next = null;
  }
}

class SinglyLinkedList {
  constructor() {
    this.head = null;
    this.size = 0;
  }

  // Insert at beginning
  insertFirst(data) {
    const newNode = new Node(data);
    newNode.next = this.head;
    this.head = newNode;
    this.size++;
  }

  // Insert at end
  insertLast(data) {
    const newNode = new Node(data);
    if (!this.head) {
      this.head = newNode;
    } else {
      let current = this.head;
      while (current.next) {
        current = current.next;
      }
      current.next = newNode;
    }
    this.size++;
  }

  // Insert at index
  insertAt(data, index) {
    if (index < 0 || index > this.size) return;
    if (index === 0) return this.insertFirst(data);
    if (index === this.size) return this.insertLast(data);

    const newNode = new Node(data);
    let current = this.head;
    let previous;
    let count = 0;

    while (count < index) {
      previous = current;
      current = current.next;
      count++;
    }

    newNode.next = current;
    previous.next = newNode;
    this.size++;
  }

  // Get at index
  getAt(index) {
    if (index < 0 || index >= this.size) return null;
    let current = this.head;
    let count = 0;
    while (count < index) {
      current = current.next;
      count++;
    }
    return current.data;
  }

  // Remove at index
  removeAt(index) {
    if (index < 0 || index >= this.size) return null;
    let current = this.head;
    if (index === 0) {
      this.head = current.next;
    } else {
      let previous;
      let count = 0;
      while (count < index) {
        previous = current;
        current = current.next;
        count++;
      }
      previous.next = current.next;
    }
    this.size--;
    return current.data;
  }

  // Clear list
  clear() {
    this.head = null;
    this.size = 0;
  }

  // Print list data
  print() {
    let current = this.head;
    while (current) {
      console.log(current.data);
      current = current.next;
    }
  }
}

// Usage Example
const list = new SinglyLinkedList();
list.insertFirst(100);
list.insertFirst(200);
list.insertLast(300);
list.insertAt(500, 1);
list.print(); // 200, 500, 100, 300
list.removeAt(2);
console.log(list.getAt(1)); // 500

Done With the Learning

Mark Singly Linked List as done and view it on your dashboard