C Data Structures: Stacks & Queues โ Array vs Linked List Implementations Masterclass
Welcome to Phase 18 (Chapter 48): C Data Structures โ Stacks & Queues, Array vs Linked List Implementations Masterclass! Stacks (LIFO) and Queues (FIFO) are the two most fundamental Abstract Data Types (ADTs) in computer science. They underpin function call management, expression parsing, task scheduling, and BFS/DFS graph traversal.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define STACK_MAX 100
typedef struct {
int data[STACK_MAX];
int top; /* Index of top element; -1 = empty */
} Stack;
void stack_init(Stack *s) { s->top = -1; }
bool stack_empty(const Stack *s){ return s->top == -1; }
bool stack_full(const Stack *s) { return s->top == STACK_MAX - 1; }
bool stack_push(Stack *s, int v) {
if (stack_full(s)) return false;
s->data[++s->top] = v;
return true;
}
bool stack_pop(Stack *s, int *out) {
if (stack_empty(s)) return false;
*out = s->data[s->top--];
return true;
}
int stack_peek(const Stack *s) { return s->data[s->top]; }
/* Application: Check balanced brackets */
bool is_balanced(const char *expr) {
Stack s; stack_init(&s);
for (int i = 0; expr[i]; i++) {
if (expr[i]=='('||expr[i]=='['||expr[i]=='{') {
stack_push(&s, expr[i]);
} else if (expr[i]==')'||expr[i]==']'||expr[i]=='}') {
if (stack_empty(&s)) return false;
int top; stack_pop(&s, &top);
if ((expr[i]==')' && top!='(')||
(expr[i]==']' && top!='[')||
(expr[i]=='}' && top!='{')) return false;
}
}
return stack_empty(&s);
}
int main(void) {
printf("is_balanced(\"[(){()}]\") = %s\n", is_balanced("[(){()}]") ? "YES" : "NO");
printf("is_balanced(\"[(])\") = %s\n", is_balanced("[(])") ? "YES" : "NO");
return 0;
}A naive array queue wastes space as front advances. A circular array queue wraps indices using modulo arithmetic, achieving O(1) enqueue and dequeue with no wasted space:
Circular Queue Index Math:
โข rear = (rear + 1) % CAPACITY โ Advance rear pointer (wraps around).
โข front = (front + 1) % CAPACITY โ Advance front pointer.
โข Full condition: (rear + 1) % CAPACITY == front
โข Empty condition: front == rear
Q1: What is a Deque (Double-Ended Queue)?
A Deque supports push/pop at BOTH front and back in O(1). Implemented with a doubly-linked list or circular array. Used for monotonic queue algorithms.
Q2: Why use linked list stack over array stack?
Linked list stack grows dynamically (no fixed capacity). Array stack has O(1) cache-friendly access but must pre-allocate maximum size.
Q3: What is the function call stack?
The CPU maintains a hardware stack (pointed to by SP register) where each function call pushes a frame containing local variables, return address, and saved registers.
Q4: How is a Queue used in BFS graph traversal?
Start by enqueuing the source node. Dequeue a node, process it, enqueue all unvisited neighbors. This guarantees visiting nodes in level-order (shortest-path-first).
Q5: What is a Priority Queue?
A Priority Queue dequeues elements by priority value, not FIFO order. Implemented with a binary heap (min-heap or max-heap). Used in Dijkstra's shortest path and task schedulers.