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
| Operation | Time Complexity | Description |
|---|---|---|
| Insertion at Head | O(1) | Add new node at beginning by updating head pointer |
| Insertion at Tail | O(n) | Traverse to end and add new node (O(1) with tail pointer) |
| Deletion at Head | O(1) | Remove first node by updating head pointer |
| Deletion by Value | O(n) | Traverse list to find and remove specific node |
| Search | O(n) | Traverse list to find element |
| Access by Index | O(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. Create new node with given data
- 2. Set new node's next to current head
- 3. Update head pointer to new node
- 4. Increment list size counter
Deletion Operations
- 1. Check if list is empty (head === null)
- 2. If deleting head, update head to head.next
- 3. For middle deletion, find previous node and update its next pointer
- 4. Decrement list size counter
- 5. Return deleted data (if needed)
Operation Visualization
| Operation | List State |
|---|---|
| Initialization | head → 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.