Singly Linked List: Node Structure and Basic Operations
A singly linked list is the simplest linked list: each node stores a value and a single next pointer to the following node, and the chain ends with a null link. You hold only the head (the first node) and walk forward from there — you can never move backward. This page builds one from the node up and covers its basic operations.
The node structure
A singly linked node carries exactly two fields: the data and one forward link.
struct Node {
int data;
Node* next;
Node(int v) : data(v), next(nullptr) {}
};
class Node {
int data;
Node next;
Node(int v) { data = v; next = null; }
}
class Node {
constructor(value) {
this.data = value;
this.next = null;
}
}
class Node:
def __init__(self, value):
self.data = value
self.next = None
Insert at the head (push-front)
Adding to the front is the linked list’s superpower: create a node, point it at the current head, and make it the new head. No shifting, O(1).
Node* pushFront(Node* head, int value) {
Node* node = new Node(value);
node->next = head; // new node points to old head
return node; // new node is the new head
}
Node pushFront(Node head, int value) {
Node node = new Node(value);
node.next = head; // new node points to old head
return node; // new node is the new head
}
function pushFront(head, value) {
const node = new Node(value);
node.next = head; // new node points to old head
return node; // new node is the new head
}
def push_front(head, value):
node = Node(value)
node.next = head # new node points to old head
return node # new node is the new head
Insert at the tail (push-back)
Without a stored tail pointer you must walk to the last node first, so a plain push-back is O(n). (Keeping a tail pointer makes it O(1) — see operations.)
Node* pushBack(Node* head, int value) {
Node* node = new Node(value);
if (head == nullptr) return node;
Node* cur = head;
while (cur->next != nullptr) cur = cur->next;
cur->next = node;
return head;
}
Node pushBack(Node head, int value) {
Node node = new Node(value);
if (head == null) return node;
Node cur = head;
while (cur.next != null) cur = cur.next;
cur.next = node;
return head;
}
function pushBack(head, value) {
const node = new Node(value);
if (head === null) return node;
let cur = head;
while (cur.next !== null) cur = cur.next;
cur.next = node;
return head;
}
def push_back(head, value):
node = Node(value)
if head is None:
return node
cur = head
while cur.next is not None:
cur = cur.next
cur.next = node
return head
Traverse and search
Walking the list visits each node once — O(n). Searching for a value is the same traversal with a comparison.
bool contains(Node* head, int target) {
for (Node* cur = head; cur != nullptr; cur = cur->next)
if (cur->data == target) return true;
return false;
}
boolean contains(Node head, int target) {
for (Node cur = head; cur != null; cur = cur.next)
if (cur.data == target) return true;
return false;
}
function contains(head, target) {
for (let cur = head; cur !== null; cur = cur.next)
if (cur.data === target) return true;
return false;
}
def contains(head, target):
cur = head
while cur is not None:
if cur.data == target:
return True
cur = cur.next
return False
Complexity summary
| Operation | Time | Notes |
|---|---|---|
| Insert at head | O(1) | no shifting |
| Insert at tail | O(n) | O(1) with a tail pointer |
| Delete at head | O(1) | repoint head |
| Search / access by index | O(n) | must walk |
| Space | O(n) | one pointer of overhead per node |
For beginners: Notice these functions return the (possibly new) head. Because inserting at the front changes which node is first, the caller must capture the returned head — otherwise the new node is lost. Many real implementations wrap the head inside a
LinkedListclass so callers never juggle it.
Pitfall: Always handle the empty list (
head == null) and the single-node cases separately. Most linked-list bugs hide in those edges.
When the singly list is enough
A singly linked list is ideal when you only move forward and mostly add/remove at the front — exactly what a stack needs. If you must also walk backward or delete a node given only a pointer to it, step up to a doubly linked list.
Next: the doubly linked list, or master every insert and delete operation.