What is a Singly Linked List?
Solution and explanation
What it is
A singly linked list is a linear data structure made of nodes. Each node contains a data field and a reference (pointer) to the next node. The first node is called the head, and the next of the last node is null, which marks the end of the list. Unlike an array, the nodes are not stored next to each other in memory; they are connected through these references, which makes insertion and deletion efficient.
head -> [ 1 | • ] -> [ 2 | • ] -> [ 3 | • ] -> [ 4 | • ] -> [ 5 | • ] -> null
data next
Understanding the node structure
Each node has two parts: the data and a pointer to the next node. This lets nodes be linked together dynamically into a chain.
// Definition of a node in a singly linked list
class Node {
int data; // the value stored in the node
Node next; // reference to the next node (null for the last node)
Node(int data) {
this.data = data;
this.next = null;
}
}
Creating a linked list of size 3 to understand how it works
Create the first node:
- Allocate memory for the first node and store data in it.
- Mark this node as head.
Create the second node:
- Allocate memory for the second node and store data in it.
- Link the first node's next to this new node.
Create the third node:
- Allocate memory for the third node and store data in it.
- Link the second node's next to this node.
- Its next stays null, so the next of the last node is null.
public class Main {
public static void main(String[] args) {
Node head = new Node(10); // first node (head of the list)
head.next = new Node(20); // link the second node
head.next.next = new Node(30); // link the third node
// Traverse and print
Node temp = head;
while (temp != null) {
System.out.print(temp.data + " -> ");
temp = temp.next;
}
System.out.println("null");
}
}
Output
10 -> 20 -> 30 -> null
Common operations and their complexity
- Traversal (visit every node): O(n) time, O(1) space.
- Search for a key: O(n) – no index, so you walk from the head.
- Insert at the beginning: O(1) – new node points to the old head.
- Insert at the end: O(n) with only a head; O(1) if you keep a tail pointer.
- Insert at a given position: O(n) to reach the position, then O(1) to relink.
- Delete from the beginning: O(1) – move head to head.next.
- Delete from the end or a position: O(n) – you need the previous node.
- Access the k-th element: O(n) (arrays do this in O(1)).
- Reverse: O(n) time, O(1) space.
// Traversal and search
static boolean search(Node head, int key) {
for (Node cur = head; cur != null; cur = cur.next) {
if (cur.data == key) return true;
}
return false;
}
// Length of the list
static int length(Node head) {
int count = 0;
for (Node cur = head; cur != null; cur = cur.next) count++;
return count;
}
Linked list versus array
- Size: an array has a fixed size (or must be copied to grow); a linked list grows one node at a time.
- Access: array[i] is O(1); the i-th node of a list is O(n).
- Insert/delete at the front: array O(n) (shift elements); list O(1).
- Memory: arrays are contiguous and cache-friendly; list nodes are scattered and each stores an extra pointer.
Advantages
- Dynamic size: no fixed limit like arrays.
- Efficient insertion and deletion at the beginning (and at the end with a tail pointer). Insertion in the middle is also O(1) if you already have a reference to the node after which you insert.
- Used to build other data structures: stacks, queues, adjacency lists of graphs, hash-table buckets.
Disadvantages
- Extra memory for storing a pointer in every node.
- No direct or random access; you must traverse.
- Cache-unfriendly, because nodes are not stored in contiguous memory.
Applications
- Undo/redo history in editors and drawing tools.
- Music playlists and image viewers (next item).
- Implementing stacks, queues and graph adjacency lists.
- Polynomial arithmetic and sparse matrices.
- Memory management (free lists) in operating systems.
Note: always handle the empty list (head == null) and the single-node list; most linked-list bugs come from these edge cases.
