Knowledge / Computer Science and Engineering / Stacks and queues

Stacks and queues

Computer Science and Engineering (B.E./B.Tech) · Data structures · free study notes for exams, placements and interviews

In short

A stack is a linear ADT in which insertion and deletion happen at one end only (LIFO - last in, first out); a queue allows insertion at the rear and deletion at the front (FIFO - first in, first out). Both are "restricted-access" structures: the restriction is exactly what makes them O(1) per operation and what makes them the right model for recursion, expression parsing, scheduling and buffering. They are the most frequently examined data structures after arrays - GATE CS asks stack permutations, circular-queue index arithmetic and expression conversion almost every year, and placement rounds at TCS, Infosys, Wipro, Cognizant, Amazon, Microsoft, Flipkart, Zoho and Goldman Sachs routinely ask balanced parentheses, next greater element, min-stack and queue-using-two-stacks. In practice they sit inside every compiler, operating system, browser and message broker a student will ever work on.

Explained

The two ADTs: definition, operations and conditions

Implementations and their trade-offs

Variants and classification

Stacks and expressions - the most examined application

Queues in systems, and the cross-conversions asked in interviews

Performance, complexity and limitations

Key points

Formulas and examples

Array stack: push → A[++top] = x; pop → x = A[top--]; empty ⟺ top == −1; full ⟺ top == N−1; size = top + 1
Circular queue (one slot empty): rear = (rear + 1) % N on enqueue, front = (front + 1) % N on dequeue; empty ⟺ front == rear; full ⟺ (rear + 1) % N == front; max elements = N − 1
Circular queue count (front = index of first element, rear = index of last element, non-empty): count = (rear − front + N) % N + 1
Stack permutations / valid bracket sequences of n pairs: C(n) = (1/(n+1)) · C(2n, n) = (2n)! / (n! · (n+1)!) (n = number of elements or bracket pairs; dimensionless count)
Dynamic-array amortised cost: total copies for n pushes with doubling = 1 + 2 + 4 + … + 2^k ≤ 2n ⟹ amortised cost per push ≤ 3 operations = O(1)
Two stacks in one array of size N: top1 starts at −1 growing up, top2 starts at N growing down; overflow ⟺ top1 + 1 == top2; combined capacity = N
Memory per element: array stack = s bytes (element size); linked stack = s + p bytes (p = pointer size, 8 on 64-bit) plus allocator padding

Example 1 - Infix to postfix. Convert A + B * C − ( D / E + F ) * G.

TokenActionStack (bottom→top)Output
AoperandA
+push+A
Boperand+A B
** > +, push+ *A B
Coperand+ *A B C
−pop *, pop +, push −−A B C * +
(push− (A B C * +
Doperand− (A B C * + D
/top is (, push− ( /A B C * + D
Eoperand− ( /A B C * + D E
+pop /, push +− ( +A B C * + D E /
Foperand− ( +A B C * + D E / F
)pop to (−A B C * + D E / F +
** > −, push− *A B C * + D E / F +
Goperand− *A B C * + D E / F + G
endpop allA B C * + D E / F + G * −

Postfix = **A B C * + D E / F + G * −; the prefix form of the same expression is − + A * B C * + / D E F G**.

Example 2 - Postfix evaluation. Evaluate 5 6 2 + * 12 4 / −.

Example 3 - Circular queue. N = 10 slots (indices 0-9), front = 7, rear = 2, queue non-empty.

Example 4 - Stack permutations. Input 1, 2, 3, 4 pushed in that order, pops interleaved freely.

Example 5 - Deque: sliding-window maximum. Array [1, 3, −1, −3, 5, 3, 6, 7], window k = 3. Keep a deque of indices whose values decrease front→rear; drop indices that fall out of the window from the front, and pop smaller values from the rear before inserting.

Example 6 - Memory comparison. Storing 1,000,000 32-bit integers:

# Monotonic stack: next greater element, O(n)
def next_greater(a):
    res, st = [-1] * len(a), []          # st holds indices, values decreasing
    for i, v in enumerate(a):
        while st and a[st[-1]] < v:
            res[st.pop()] = v
        st.append(i)
    return res
# next_greater([4, 5, 2, 25]) -> [5, 25, 25, -1]
/* Circular queue, count-variable convention: all N slots usable */
int q[N], front = 0, rear = -1, count = 0;
int enqueue(int x){ if(count==N) return 0;            /* overflow */
    rear=(rear+1)%N; q[rear]=x; count++; return 1; }
int dequeue(int *x){ if(count==0) return 0;           /* underflow */
    *x=q[front]; front=(front+1)%N; count--; return 1; }
AspectStackQueueDeque
DisciplineLIFOFIFOboth ends
Insert / delete atsame endopposite endseither end
Pointers neededtopfront, rearfront, rear
Classic userecursion, expressions, DFS, undoscheduling, buffers, BFSsliding window, LRU, 0-1 BFS
C++ / Javastd::stack / ArrayDequestd::queue / ArrayDequestd::deque / ArrayDeque
OperationArray (static)Dynamic arrayLinked list
push / enqueueO(1)O(1) amortised, O(n) worstO(1)
pop / dequeueO(1)O(1)O(1)
peek / frontO(1)O(1)O(1)
SearchO(n)O(n)O(n)
Space overheadnoneup to 100% slack1 pointer per node
Capacityfixedgrowsgrows

Where it is used

Interview questions

Common mistakes

Related topics

Arrays and strings · Linked lists · Heaps and priority queues · Graphs and their representation · Trees and binary search trees · Recursion and backtracking

Open in the Knowledge reader →Find jobs →