Stack Implemented By Linked List

data structures algorithms programming fundamentals software engineering memory management
A stack is a Last-In, First-Out (LIFO) data structure. Implementing a stack with a linked list uses the list’s head as the stack top, enabling O(1) push and pop without resizing. This approach offers dynamic capacity at the cost of per-node pointer overhead and frequent small allocations.

Overview

A stack is a Last-In, First-Out (LIFO) data structure: the most recently added element is the first one removed. Implementing a stack with a linked list is a simple and efficient way to support constant-time insertion and removal at the top by using the list’s head as the stack top.

Why Use a Linked List for a Stack?

  • Dynamic size: Grows and shrinks on demand without resizing or pre-allocating capacity.
  • O(1) push/pop: Inserting/removing at the head is constant time.
  • Simple implementation: Only a head pointer and a node structure are required.
  • Trade-offs: Extra pointer per node; potentially more heap allocations and less cache locality than an array-based stack.

Core Operations

  • push(x): Insert x at the head; head becomes the new node.
  • pop(): Remove and return the head value; update head to head.next.
  • peek() or top(): Return the head value without removal.
  • is_empty(): Check if head is null.
  • size(): Track the number of elements.

How It Works

Structure Node:
    value
    next

Structure StackLL:
    head = null
    n = 0

    push(x):
        node = new Node
        node.value = x
        node.next = head
        head = node
        n = n + 1

    pop():
        if head is null: raise Underflow
        x = head.value
        head = head.next
        n = n - 1
        return x

    peek():
        if head is null: raise Underflow
        return head.value

    is_empty():
        return head is null

    size():
        return n

Visual intuition:

top -> [value: 7 | next] -> [value: 3 | next] -> [value: 1 | next] -> null

Complexity

  • Time: push O(1), pop O(1), peek O(1), is_empty O(1)
  • Space: O(n) for n elements, plus per-node pointer overhead

Implementation Notes

  • Singly vs doubly linked: A singly linked list is sufficient; you only need fast access to the top.
  • Sentinel (dummy) head: Optional; can simplify edge-case checks at the cost of one extra node.
  • Error handling: Decide how to handle underflow (exceptions, error codes, or a special value if the type permits).
  • Memory management: In manual memory languages, ensure popped nodes are freed; otherwise, you risk leaks.
  • Thread safety: Not thread-safe by default; add synchronization if used concurrently.
  • Generics: Parameterize the value type for type safety.

Comparison: Linked List Stack vs Array-Based Stack

  • Linked list: No resizing; stable O(1) push/pop; extra pointer per node; more allocations.
  • Array: Better cache locality; may need resizing; push can be amortized O(1); fixed capacity if not resizable.

Small Python Example

class Node:
    def __init__(self, value, next=None):
        self.value = value
        self.next = next

class StackLL:
    def __init__(self):
        self._head = None
        self._size = 0

    def push(self, x):
        self._head = Node(x, self._head)
        self._size += 1

    def pop(self):
        if self._head is None:
            raise IndexError
        x = self._head.value
        self._head = self._head.next
        self._size -= 1
        return x

    def peek(self):
        if self._head is None:
            raise IndexError
        return self._head.value

    def is_empty(self):
        return self._head is None

    def __len__(self):
        return self._size

Use Cases

  • Expression evaluation and parsing (postfix, prefix, infix conversions)
  • Balanced parentheses and delimiter checking
  • Backtracking and depth-first search helpers
  • Undo and redo functionality

Common Pitfalls

  • Forgetting to update the head on push or pop.
  • Not handling underflow when popping or peeking an empty stack.
  • Memory leaks in manual memory environments by not freeing nodes.
  • Using tail operations, which turn pop into O(n); always operate at the head.

Context from Referenced By

Context from Related Topics
Pop Quiz
Topic: stack_implemented_by_linked_list
Level: 1
True or False:

Using the linked list’s head as the stack top allows push and pop to run in O(1) time without any resizing.

Topic: stack_implemented_by_linked_list
Level: 1
Multiple Choice:

In a stack implemented with a singly linked list, which design choice would cause pop() to degrade from O(1) to O(n)?

Topic: stack_implemented_by_linked_list
Level: 1
Fill in the Blank:

Attempting to pop from an empty linked-list stack should raise an _____ condition.

Topic: stack_implemented_by_linked_list
Level: 2
True or False:

A singly linked list is sufficient to implement a stack because only the head needs to be accessed for push and pop operations.

Topic: stack_implemented_by_linked_list
Level: 2
Multiple Choice:

Which of the following is a disadvantage of using a linked list to implement a stack compared to an array-based stack?

Topic: stack_implemented_by_linked_list
Level: 2
Fill in the Blank:

Adding a sentinel (dummy) head node to a linked-list stack primarily helps simplify _____ at the cost of one extra node.

Topic: stack_implemented_by_linked_list
Level: 3
True or False:

A linked-list-based stack is not thread-safe by default and requires synchronization for safe concurrent use.

Topic: stack_implemented_by_linked_list
Level: 3
Multiple Choice:

In a linked-list-based stack, what design choice ensures that size() runs in O(1) time?

Topic: stack_implemented_by_linked_list
Level: 3
Fill in the Blank:

In a linked-list-based stack implemented in a manual memory language, failing to free nodes after pop() can lead to _____.

Topic: stack_implemented_by_linked_list
Level: 4
True or False:

Switching from a singly linked list to a doubly linked list provides no asymptotic performance advantage for push, pop, or peek in a stack.

Topic: stack_implemented_by_linked_list
Level: 4
Multiple Choice:

When implementing push(x) for a stack backed by a singly linked list, which sequence of pointer updates correctly adds x to the top without losing the existing stack?

Topic: stack_implemented_by_linked_list
Level: 4
Fill in the Blank:

Compared to an array-based stack, a linked-list-based stack typically has worse _____, potentially reducing performance on modern CPUs.

Topic: stack_implemented_by_linked_list
Level: 5
True or False:

In a linked-list-based stack, peek returns the top element in O(1) time without altering the stack.

Topic: stack_implemented_by_linked_list
Level: 5
Multiple Choice:

Why are push operations on a linked-list-based stack worst-case O(1) while push on a resizable array-based stack is only amortized O(1)?

Topic: stack_implemented_by_linked_list
Level: 5
Fill in the Blank:

In a linked-list-based stack, is_empty() typically returns true when the _____ is null.

Next Topic
implements
0.94

Stack Adt
This linked-list-based approach realizes the Stack ADT’s LIFO semantics by using the list head as the stack top, enabling O(1) push/pop and dynamic sizing.
depends_on
0.92

Linked List
Implementing a stack this way requires the linked list’s node structure and O(1) head operations to support push and pop.
used_by
0.88

Balanced Parentheses Check
Balanced parentheses checking uses a stack to push opening symbols and pop on matching closers; a linked-list backed stack provides O(1) push/pop and dynamic capacity for arbitrarily long inputs.
used_by
0.86

Undo Redo
Undo/redo systems commonly use one or two stacks to track action history; a linked-list-based stack provides O(1) push/pop and dynamic growth without resizing, fitting variable-length histories.
used_by
0.82

Depth First Search
Iterative depth-first search uses a stack to manage the frontier; a linked-list-based stack offers O(1) push/pop and dynamic capacity during traversal.
used_by
0.82

Backtracking
Backtracking algorithms often manage decision states with a stack; a linked-list-based stack provides O(1) push/pop and dynamic depth when the search space is unpredictable.
used_by
0.8

Evaluate Postfix
Postfix expression evaluation uses a stack to push operands and pop them on operators; a linked-list-based stack offers O(1) operations and dynamic capacity during evaluation.
used_by
0.67

Expression Parsing
Expression parsing algorithms (e.g., shunting-yard, infix-to-postfix, syntax checking) rely on a stack to manage operators and operands; a linked-list-backed stack supports this with O(1) push/pop and dynamic growth.