androidengineers.Book a session

Linked Lists

Singly vs Doubly Linked Lists

article25 minMedium

Linked lists come in several structural varieties. The two most common are the Singly Linked List (unidirectional) and the Doubly Linked List (bidirectional).


Singly Linked List (SLL)

In a Singly Linked List, each node points only forward to its successor (next).

Head
 |
 v
[ 10 | * ] ---> [ 20 | * ] ---> [ 30 | null ]

Advantages:

  • Smaller Memory Footprint: Only one reference pointer (next) per node.
  • Simpler implementation with fewer pointer updates during insertion and deletion.

Limitations:

  • One-way traversal: You cannot step backward.
  • Deletion is awkward: Deleting a given node N requires traversing from head to find the node immediately preceding N in O(n) time.

Doubly Linked List (DLL)

In a Doubly Linked List, each node maintains two reference pointers:

  1. next: Points to the successor node.
  2. prev: Points to the predecessor node.
Head                                         Tail
 |                                            |
 v                                            v
null <-- [ * | 10 | * ] <===> [ * | 20 | * ] <===> [ * | 30 | * ] --> null

In Kotlin:

class DoublyNode<T>(
    var data: T,
    var prev: DoublyNode<T>? = null,
    var next: DoublyNode<T>? = null
)

Deletion Comparison: The Decisive Advantage of DLL

Consider deleting a node target when you already hold a direct reference to it:

In Singly Linked List: O(n)

You cannot modify prev.next because you don't know who prev is! You must scan from head:

// Singly Linked List: O(n) traversal needed to find predecessor
fun deleteNode(head: Node<T>, target: Node<T>) {
    var curr = head
    while (curr.next != null && curr.next != target) {
        curr = curr.next!!
    }
    curr.next = target.next // Bypass target
}

In Doubly Linked List: O(1)

Because the node knows its predecessor (node.prev), removal is instantaneous:

// Doubly Linked List: O(1) constant time removal!
fun deleteNode(target: DoublyNode<T>) {
    target.prev?.next = target.next
    target.next?.prev = target.prev
    target.prev = null
    target.next = null
}

This O(1) node self-deletion is why LRU Caches and Android Navigation Stacks rely on Doubly Linked Lists.


Comprehensive Comparison Matrix

FeatureSingly Linked ListDoubly Linked List
Pointers per node1 (next)2 (prev, next)
Memory per nodeLower (~24 bytes)Higher (~32–40 bytes)
Traversal DirectionForward onlyForward and Backward
Insert / Delete at HeadO(1)O(1)
Insert / Delete at TailO(1) (with tail pointer)O(1)
Delete arbitrary node (given node pointer)O(n) (must find predecessor)O(1)
Reverse traversalRequires recursion/stack (O(n))O(1) directly via prev

Summary

  • Choose Singly Linked Lists when memory is constrained and traversal is strictly forward (e.g., hash collision buckets).
  • Choose Doubly Linked Lists when bidirectional navigation or O(1) node removal is needed (e.g., LRU cache, text editor cursors).

YOUR LEARNING JOURNEY

0 of 55 available lessons completed

Progress saved in this browser. No account needed.
Singly vs Doubly Linked Lists | Data Structures | Android Engineers