Skip to main content
Data Structures•Last Updated : 09 Oct 2026
~30 min read

Stacks, Queues & Monotonic Sequences

Constrained linear structures: call stack simulation, circular array ring buffers, expression bracket balancing, and linear O(N) monotonic stacks for next greater element.

1. Invariants of LIFO and FIFO Data Structures

Stacks and Queues are constrained linear data structures with strict element insertion and removal semantics.

The Stack Invariant (LIFO - Last-In, First-Out):

Elements are added and removed strictly from one boundary called the Top. The last element pushed is guaranteed to be the first element popped. Stacks form the basis of CPU function call frames, backtracking, and expression parsing (Dijkstra's Shunting Yard algorithm).

The Queue Invariant (FIFO - First-In, First-Out):

Elements are inserted at the Tail (Enqueue) and removed strictly from the Head (Dequeue). Queues model fair asynchronous scheduling, web server thread pools, and Breadth-First Search (BFS) graph traversals.

1def is_valid_parentheses(s: str) -> bool:
2 """Validates balanced bracket sequence using a LIFO stack in O(N) time and O(N) space."""
3 mapping = {')': '(', '}': '{', ']': '['}
4 stack = []
5
6 for char in s:
7 if char in mapping:
8 # Closing bracket: top must match
9 top_element = stack.pop() if stack else '#'
10 if mapping[char] != top_element:
11 return False
12 else:
13 # Opening bracket: push onto stack
14 stack.append(char)
15
16 return len(stack) == 0
17
18# Tests
19print('"{[()]}" -> Valid:', is_valid_parentheses("{[()]}"))
20print('"([)]" -> Valid:', is_valid_parentheses("([)]"))
Output
"{[()]}" -> Valid: True
"([)]"   -> Valid: False

2. Circular Queue (Ring Buffer) Memory Layout

Implementing a queue with a naive dynamic array causes O(N) dequeue operations due to shifting elements.

A Ring Buffer (Circular Queue) eliminates shifts by wrapping head and tail pointers using modulo arithmetic: next_index = (current_index + 1) % Capacity. Both enqueue and dequeue execute in deterministic O(1) time with zero memory churn.

Stack vs Queue vs Deque Complexity Comparison

Data StructurePush / EnqueuePop / DequeuePeek / FrontMemory Overhead
Stack (Array-backed)O(1) AmortizedO(1)O(1)Contiguous (Minimal)
Queue (Ring Buffer)O(1)O(1)O(1)Fixed Array (Zero GC)
Queue (Linked List)O(1)O(1)O(1)24 bytes/node pointer overhead
Double-Ended Queue (Deque)O(1) Front & BackO(1) Front & BackO(1)Chunked Array Pages
Asymptotic runtimes for linear constrained structures

Quick Syntax & Reference Sheet

Concept / RuleSyntax / Usage
Stack Operationsstack.append(x) # push O(1) stack.pop() # pop O(1) stack[-1] # peek O(1)
Ring Buffer Modulo Arithmetictail = (tail + 1) % CAPACITY head = (head + 1) % CAPACITY

Common Pitfalls & Developer Mistakes

✕ Mistake 1:

Popping from an Empty Stack or Dequeuing from Empty Queue

Why it happens:

Correction:
✕ Mistake 2:

Using a Naive Python List as a Queue via `list.pop(0)`

Why it happens:

Correction:

Frequently Asked Questions

What is a Monotonic Stack?

A monotonic stack maintains elements in strictly increasing or decreasing order. It is the optimal data structure to solve 'Next Greater Element', 'Daily Temperatures', and 'Largest Rectangle in Histogram' problems in linear O(N) time.

Why is ArrayDeque preferred over LinkedList for queues in Java?

ArrayDeque stores elements contiguously, achieving superior CPU cache locality and zero node allocation overhead compared to LinkedList.
Article Tags:#Stacks#Queues#Ring Buffer#LIFO#FIFO#Monotonic Stack
Was this lesson clear and helpful?

Discussion (0)

Sign in to ask questions and reply.
Loading discussion…
Discuss in community