LearnAbout

Singly Linked List

On this page
Quick reference
Insert at headO(1)
Insert at tailO(n)
Search / access by valueO(n)
Delete by valueO(n)
Reverse whole listO(n)
Cycle detectionO(n)
The Idea

An array is a row of numbered lockers β€” you can walk straight to locker #47 because you know exactly where it sits. A linked list is a scavenger hunt: each clue tells you the next clue's location, but never all of them. To find the fifth clue you must have already found the first four; there is no locker number to jump to.

Each stop is a node: a value plus a pointer β€” the address of the next node, or NULL if the hunt ends. The list itself only remembers where the hunt starts: a pointer called head. Lose the head and the whole chain is unreachable, even though every node still exists in memory.

Arrays are fast to read but inserting mid-array means shifting every element after it; a linked list just rewrites two pointers β€” you trade fast random access for cheap insertion/deletion once your hand is already on the right node.
Build It
Structures
structure Node:
    value
    next          // -> another Node, or NULL

structure LinkedList:
    head          // -> first Node, or NULL if empty
insertAtHead β€” O(1)
function insertAtHead(list, value):
    newNode = Node(value)
    newNode.next = list.head   // point at old start (may be NULL β€” that's fine)
    list.head = newNode        // new node becomes the start
insertAtTail β€” O(n) without a tail pointer
function insertAtTail(list, value):
    newNode = Node(value)
    if list.head is NULL:      // empty list β€” new node IS the list
        list.head = newNode
        return
    curr = list.head
    while curr.next is not NULL:  // walk until curr is the last node
        curr = curr.next
    curr.next = newNode
deleteValue β€” first match, O(n)
function deleteValue(list, target):
    if list.head is NULL:
        return                  // nothing to delete
    if list.head.value == target:
        list.head = list.head.next   // deleting the head moves head forward
        return
    prev = list.head
    while prev.next is not NULL:
        if prev.next.value == target:
            prev.next = prev.next.next   // skip over the target node
            return
        prev = prev.next
reverse β€” O(n) time, O(1) space
function reverse(list):
    prev = NULL
    curr = list.head
    while curr is not NULL:
        nextNode = curr.next   // save it before we overwrite curr.next
        curr.next = prev       // flip the arrow backward
        prev = curr
        curr = nextNode
    list.head = prev           // old tail is the new head
Three pointers, one pass, nothing extra allocated β€” this is the pattern almost every linked-list trick builds on.
hasCycle β€” Floyd's slow/fast pointer, O(n) time, O(1) space
function hasCycle(list):
    slow = list.head
    fast = list.head
    while fast is not NULL and fast.next is not NULL:
        slow = slow.next          // walks 1 step
        fast = fast.next.next     // walks 2 steps
        if slow == fast:
            return true      // fast lapped slow β€” must be a loop
    return false             // fast hit NULL β€” the chain has an end
Know It

The pattern to memorize: anything that only touches the head is O(1). Anything that has to walk to find a spot is O(n). Nothing here ever needs more than a handful of pointers, so space is O(1) across the board.

OperationTimeSpaceWhy
Insert at headO(1)O(1)Rewrite one pointer. Never touches the rest of the chain.
Insert at tailO(n)O(1)Must walk to the last node first β€” unless the list keeps a separate tail pointer, which drops this to O(1) too.
Search / access by valueO(n)O(1)No index to jump to β€” you must follow pointers from head, one node at a time.
Delete by valueO(n)O(1)Finding the node is O(n); once found, unlinking it is O(1).
Reverse whole listO(n)O(1)Visit each node exactly once, flip its arrow, move on.
Cycle detectionO(n)O(1)Two pointers at different speeds meet within one lap of the cycle β€” no extra memory needed to remember visited nodes.
Break It

Empty

head is NULL
HEAD→NULL

Every operation's first check: delete-from-empty, search-in-empty, reverse-an-empty-list must all return cleanly instead of dereferencing a node that doesn't exist.

Single node

head.next is NULL
HEAD→3‒→NULL

Deleting the only node means the list must become empty again β€” head itself has to change, not just some node's pointer. Common bug: code that only ever edits prev.next and never handles "there is no prev."

Value not found

walking off the end
HEAD→1‒→NULL

Search and delete must terminate on NULL, not just "when found." Forgetting the NULL check turns a missing value into a crash instead of a clean "not found."

Cycle

a node points backward into the chain
HEADβ†’3β€’β†’7β€’β†’1‒↩ back to 3

next never becomes NULL, so a plain while-loop search runs forever β€” exactly why Floyd's slow/fast pointer exists: two walkers at different speeds are guaranteed to meet if a loop exists, with no extra memory.

Use It
Reverse Linked List
The reverse() pattern above, verbatim: prev/curr/next, one pass.
Easy
Merge Two Sorted Lists
Dummy head node, splice smaller-front nodes across without copying values.
Easy
Linked List Cycle
hasCycle() as-is: slow/fast pointers, return true the moment they meet.
Easy
Middle of the Linked List
Fast/slow pointers again β€” when fast hits the end, slow sits at the middle.
Easy
Remove Duplicates from Sorted List
Compare each node to node.next; skip forward when they match.
Easy
Intersection of Two Linked Lists
Walk both lists; when one hits NULL, redirect it to the other list's head β€” lengths equalize.
Easy
Delete Node in a Linked List
No access to head or prev β€” copy the next node's value over yours, then skip it.
Easy
Palindrome Linked List
Find the middle, reverse the second half in place, walk both halves inward.
Easy
Linked List Cycle II
After slow/fast meet, reset one pointer to head β€” both now reach the cycle's start at the same pace.
Medium
Remove Nth Node From End of List
Two pointers n nodes apart; when the lead hits NULL, the trailer is right before the target.
Medium
Odd Even Linked List
Re-link nodes into two chains by position parity, then join the chains at the end.
Medium
Add Two Numbers
Walk both lists together, digit by digit, carrying overflow into a new list.
Medium
Swap Nodes in Pairs
Dummy head, then rewire three pointers per pair β€” draw it before you code it.
Medium
Rotate List
Find the length, join tail to head to form a ring, then break it at the new head.
Medium
Partition List
Build two separate chains (less-than / greater-or-equal), then splice them together.
Medium