CMD Guide
HomeDSAStack

Implementing Stack Data Structure

A stack is an array or linked list restricted so that all insertion and removal happens at a single end (the top) — that restriction is what makes every operation O(1): there is never a need to shift elements or search, because the only mutable position is the last one written.

Recognize the pattern

Brute force → optimal

Brute force: use a dynamic array but always insert/remove at index 0 to visually mimic "newest on top". Every push/pop shifts every remaining element by one slot — O(n) time per operation because the array must stay contiguous from index 0.

Optimal: insert/remove at the tail of the array (or the head of a singly linked list) instead. Nothing after the top element needs to move, so push/pop/peek become O(1).

Complexity, derived from first principles

Array-backed stack: push/pop/peek touch exactly one index (top) — one read or write, no loop → O(1) time. When the backing array fills, we allocate a new array of double the size and copy n elements: that copy costs O(n), but it happens only once every n pushes since the previous resize, so the amortized cost per push is O(n)/n = O(1).

More rigorously (potential method, informally): define potential Φ = 2·size − capacity. A non-resizing push does O(1) real work and increases size by 1, so Φ rises by 2 — 1 unit pays for the work done, 1 unit is banked as credit. By the time the array is full and a resize triggers, size == capacity == n, so Φ = n; that banked credit exactly covers the O(n) cost of copying n elements during the resize, keeping amortized cost (real cost + ΔΦ) at O(1) per push over any sequence. Space is O(n) for n stored elements; the array never shrinks, so up to 2n slots can be allocated at any time even if only n are occupied.

Linked-list-backed stack: push/pop operate on the head pointer only — O(1) time, no amortization needed since no resize/copy ever happens. Space is O(n) for n nodes, plus real per-node overhead: each Node object carries roughly a 16-byte object header (typical 64-bit JVM) plus its field(s). The next reference itself is 4 bytes, not 8, under compressed oops — the JVM's default for heaps under ~32GB — but that per-pointer saving is dwarfed by the header, so realistic overhead is closer to 16–24 bytes per node depending on JVM and padding. Either way, this is more per-element overhead than the array version, which has none once allocated.

Traced worked example (array-backed, capacity starts at 2)

OpArray statetopcapacityNote
push(10)[10]02fits
push(20)[10,20]12fits exactly, now full
push(30)[10,20,30,_]24resize 2→4, copy 2 elems, then insert
peek()[10,20,30,_]24returns 30, no mutation
pop()[10,20,_,_]14returns 30, top--, then slot nulled purely to drop the object reference for GC — this stack stores only references (Object[]), so there is no primitive-array behavior here
isEmpty()[10,20,_,_]14false

Java: array-based stack

public class ArrayStack<T> {
    private Object[] data;
    private int top = -1; // index of top element, -1 = empty

    public ArrayStack(int capacity) { data = new Object[capacity]; }

    public void push(T val) {
        // Math.max(1, ...) guards the capacity == 0 case: doubling a
        // zero-length array stays zero-length, which would then write
        // out of bounds below.
        if (top + 1 == data.length) resize(Math.max(1, data.length * 2));
        data[++top] = val;
    }

    @SuppressWarnings("unchecked")
    public T pop() {
        if (isEmpty()) throw new RuntimeException("stack underflow");
        T val = (T) data[top];
        data[top--] = null; // drop reference so GC can reclaim it
        return val;
    }

    @SuppressWarnings("unchecked")
    public T peek() {
        if (isEmpty()) throw new RuntimeException("stack underflow");
        return (T) data[top];
    }

    public boolean isEmpty() { return top == -1; }

    private void resize(int newCap) {
        Object[] bigger = new Object[newCap];
        System.arraycopy(data, 0, bigger, 0, data.length);
        data = bigger;
    }
}

Java: linked-list-based stack

public class LinkedStack<T> {
    private static class Node<T> {
        T val; Node<T> next;
        Node(T val, Node<T> next) { this.val = val; this.next = next; }
    }
    private Node<T> head; // head IS the top
    private int size = 0;

    public void push(T val) { head = new Node<>(val, head); size++; }

    public T pop() {
        if (isEmpty()) throw new RuntimeException("stack underflow");
        T val = head.val;
        head = head.next;
        size--;
        return val;
    }

    public T peek() {
        if (isEmpty()) throw new RuntimeException("stack underflow");
        return head.val;
    }

    public boolean isEmpty() { return head == null; }
}

Pitfalls

When to use / when not — array vs linked list

Use the array-backed stack when you want cache-friendly contiguous memory and don't need to share nodes; it has zero per-element pointer overhead and better constants despite occasional O(n) resizes. (java.util.ArrayDeque gets similar cache-friendliness, but via a circular buffer with independent head and tail indices that wrap around a fixed-then-grown array — a different mechanism from the single growing top-pointer array taught here, not the same design.) Use the linked-list-backed stack when you need guaranteed O(1) worst case per operation (no resize spikes — relevant for hard real-time systems) or when elements must be large/movable objects that shouldn't be copied during a resize. Avoid a hand-rolled stack altogether for general use in Java — prefer ArrayDeque (faster, no null issues) over the legacy java.util.Stack (synchronized, extends Vector, slower).

Takeaways

Recall: Why is a single push on an array-backed stack described as "amortized O(1)" rather than worst-case O(1), and what specific operation causes the worst case?


Synthesized from standard stack-implementation teaching (array vs. linked-list backing, push/pop/peek/isEmpty) and extended with a potential-method amortized-cost derivation, a corrected traced example, JVM memory-layout accuracy (compressed oops, object headers), a capacity-0 edge-case fix, and array-vs-linked-list trade-off analysis per the study guide's depth bar.

🤖 Don't fully get this? Learn it with Claude

Stuck on Implementing Stack Data Structure? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Implementing Stack Data Structure** (DSA) and want to truly understand it. Explain Implementing Stack Data Structure from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Implementing Stack Data Structure** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Implementing Stack Data Structure** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Implementing Stack Data Structure** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes