Skip to content
← All posts

Stacks and Queues: LIFO vs FIFO

7 min read
data-structuresstackspatterns

Stacks and queues are two of the most fundamental data structures in computer science, and they show up constantly in coding interviews. They are both simple. They both store a collection of elements. But the order in which they let you access those elements is completely different, and that difference is what makes each one useful for different kinds of problems.

If you have ever wondered about stack vs queue, when to reach for one over the other, or how to spot them in interview problems, this post covers it all.

LIFO vs FIFO: the core difference

The entire distinction between stacks and queues comes down to two acronyms:

  • Stack = LIFO (Last In, First Out). The most recently added element is the first one removed. Think of a stack of plates: you put new plates on top and take from the top.
  • Queue = FIFO (First In, First Out). The earliest added element is the first one removed. Think of a line at a coffee shop: the first person in line gets served first.

That is it. Everything else flows from this single difference.

Stack (LIFO)topABCpushpopLast In, First OutQueue (FIFO)frontbackABCenqueuedequeueFirst In, First Out
Stack vs. Queue: a stack accesses from one end (the top), while a queue processes from the front and adds to the back.

Watching them side by side

The best way to internalize LIFO FIFO is to see the same sequence of operations on both structures at the same time. Let's add A, B, and C to each, then remove everything and compare what comes out.

Step 1: Push A onto stack. Enqueue A into queue.

stackAqueueA

Both structures now contain one element: A.

Step 2: Push B. Enqueue B.

stackBAqueueAB

Stack: B is on top. Queue: B goes to the back.

Step 3: Push C. Enqueue C.

stackCBAqueueABC

Three items in each. Now let's remove one and see the difference.

Step 4: Pop from stack. Dequeue from queue.

stackBAqueueBC

Stack popped C (last in). Queue dequeued A (first in). This is the core difference.

Step 5: Pop again. Dequeue again.

stackAqueueC

Stack popped B. Queue dequeued B. The removal order is reversed.

Step 6: Pop the last item. Dequeue the last item.

stackemptyqueueempty

Stack popped A (first in, last out). Queue dequeued C (last in, last out). Both empty.

Notice the punchline: we inserted A, B, C into both structures in the same order. The stack gave them back as C, B, A (reversed). The queue gave them back as A, B, C (original order). That reversal property is exactly why stacks are useful for problems involving undo, backtracking, and nesting.

Stack operations and complexity

A stack supports two main operations:

OperationWhat it doesTime
push(x)Add x to the topO(1)
pop()Remove and return the top elementO(1)
peek() / top()Look at the top element without removing itO(1)
isEmpty()Check if the stack is emptyO(1)

Everything is O(1). That is what makes stacks so efficient. You never need to search, shift, or resize (assuming a reasonable implementation).

Array-based stack (Python)

In Python, a list works perfectly as a stack. append() pushes, pop() removes from the end. Both are amortized O(1).

stack = []
stack.append(10)   # push 10
stack.append(20)   # push 20
stack.append(30)   # push 30

top = stack[-1]    # peek: 30
val = stack.pop()  # pop: 30
# stack is now [10, 20]

In Python, always use append() and pop() (no argument) for stack operations. Never use insert(0, x) or pop(0) on a list. Those are O(n) because they shift every element.

Linked-list-based stack

You can also build a stack with a linked list by always inserting and removing at the head. Each operation is O(1) with no amortization needed.

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

class LinkedStack:
    def __init__(self):
        self.head = None

    def push(self, val):
        self.head = Node(val, self.head)

    def pop(self):
        if not self.head:
            raise IndexError("pop from empty stack")
        val = self.head.val
        self.head = self.head.next
        return val

    def peek(self):
        if not self.head:
            raise IndexError("peek at empty stack")
        return self.head.val

When would you use a linked-list stack over an array stack? In practice, almost never in Python. The built-in list is fast enough. But in languages where dynamic arrays are expensive or when you need guaranteed O(1) per operation (no amortized resizing), a linked-list stack can be the better choice.

Queue operations and complexity

A queue also supports O(1) operations, but from two different ends:

OperationWhat it doesTime
enqueue(x)Add x to the backO(1)
dequeue()Remove and return the front elementO(1)
peek() / front()Look at the front element without removing itO(1)
isEmpty()Check if the queue is emptyO(1)

Array-based queue (Python)

Here is the catch: a plain Python list is a bad queue. list.pop(0) is O(n) because it shifts every remaining element. Instead, use collections.deque, which is a double-ended queue with O(1) operations on both ends.

from collections import deque

q = deque()
q.append(10)      # enqueue 10
q.append(20)      # enqueue 20
q.append(30)      # enqueue 30

front = q[0]      # peek: 10
val = q.popleft()  # dequeue: 10
# q is now deque([20, 30])

A common interview mistake: using list.pop(0) for a queue. Interviewers notice this because it turns an O(n) algorithm into O(n^2). Always use deque for queues in Python.

Linked-list-based queue

With a linked list, you keep a pointer to both the head (front) and tail (back). Enqueue at the tail, dequeue from the head. Both O(1).

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

class LinkedQueue:
    def __init__(self):
        self.head = None
        self.tail = None

    def enqueue(self, val):
        node = Node(val)
        if self.tail:
            self.tail.next = node
        self.tail = node
        if not self.head:
            self.head = node

    def dequeue(self):
        if not self.head:
            raise IndexError("dequeue from empty queue")
        val = self.head.val
        self.head = self.head.next
        if not self.head:
            self.tail = None
        return val

When to use a stack vs a queue

This is the practical question that matters for interviews. Here is a quick decision guide:

Reach for a stack when:

  • You need to match or validate nested structures (parentheses, HTML tags, expressions)
  • You need to process elements in reverse order
  • You need to undo or backtrack to a previous state
  • The problem asks about the next/previous greater or smaller element (monotonic stack)
  • You are converting recursion to an iterative approach

Reach for a queue when:

  • You need to process elements in the order they arrived (BFS, task scheduling)
  • The problem involves levels or layers (level-order tree traversal, shortest path in unweighted graph)
  • You are implementing breadth-first search on a graph or grid
  • The problem involves topological ordering of dependencies

Here is a handy mental model: if the problem feels like "go deep first, then come back" (DFS), use a stack. If it feels like "process everything at this distance before going further" (BFS), use a queue.

Stack interview problems

Stacks show up in a huge range of interview problems. Here are some of the most important ones to master:

Matching and validation

  • Valid Parentheses - The classic stack problem. Push openers, pop when you see a closer, verify the match. This is the first stack problem you should know cold.

Monotonic stack

  • Daily Temperatures - For each day, find how many days until a warmer temperature. The monotonic stack pattern processes elements in one pass by maintaining a stack in sorted order.

Design problems

  • Min Stack - Design a stack that supports getMin() in O(1). The trick is maintaining an auxiliary stack that tracks the current minimum at each level.

Going deeper

For a comprehensive breakdown of every stack pattern (bracket matching, monotonic stacks, state save/restore), check out the Stack Patterns guide. It covers the techniques that apply across all stack problems.

Queue interview problems

Queues are the backbone of breadth-first search, which makes them essential for graph and grid problems:

BFS on grids

  • Number of Islands - Count connected components in a 2D grid. BFS with a queue explores each island level by level, marking visited cells as you go. (This problem can also be solved with DFS, but the BFS approach is a great way to practice queues.)

Topological sort

  • Course Schedule - Given prerequisite pairs, determine if you can finish all courses. This is cycle detection via topological sort, and the BFS version (Kahn's algorithm) uses a queue to process nodes with zero in-degree.

Stacks and queues compared

Here is a side-by-side summary of everything we have covered:

StackQueue
OrderLIFO (Last In, First Out)FIFO (First In, First Out)
Addpush (to top)enqueue (to back)
Removepop (from top)dequeue (from front)
Pythonlist with append()/pop()collections.deque with append()/popleft()
Use casesMatching, backtracking, DFSBFS, scheduling, level-order
Key pattern"Most recent first""Oldest first"

Building fluency with stacks and queues

Understanding stack vs queue conceptually is the easy part. The hard part is writing the code quickly and correctly under interview pressure. You need to be able to implement a monotonic stack without thinking, reach for deque automatically for BFS, and recognize which data structure a problem needs within the first minute of reading it.

That is where deliberate, spaced practice makes the difference. Instead of reading about LIFO FIFO once and hoping it sticks, you practice the core operations and stack queue interview problems at increasing intervals. Each time you drill, you reinforce the pattern a little more until it becomes automatic.

CodeBricks breaks these problems into their reusable building blocks and schedules them with spaced repetition. You type the code from scratch each session, and the spacing adapts to how well you actually remember each piece.

Related posts