Loading...
Development

With Code Examples, Structures, Diagrams & Applications

Complete Notes on Stacks and Queues

With Code Examples, Structures, Diagrams & Applications


1. STACK

Definition

LIFO (Last In, First Out)
The last element added is the first one to be removed.


Analogy

A stack of plates: You push a plate on top, and pop from the top.

    [Plate 3] ← Top
    [Plate 2]
    [Plate 1]

Basic Operations

OperationDescriptionTime Complexity
push(x)Insert element, x at topO(1)
pop()Remove and return topO(1)
peek() / top()View top elementO(1)
isEmpty()Check if stack is emptyO(1)
size()Return number of elementsO(1)

Implementation 1: Array-Based Stack

#include <stdio.h>
#define MAX 100

typedef struct {
    int arr[MAX];
    int top;
} Stack;

void initStack(Stack* s) {
    s->top = -1;
}

int isEmpty(Stack* s) {
    return s->top == -1;
}

int isFull(Stack* s) {
    return s->top == MAX - 1;
}

void push(Stack* s, int data) {
    if(isFull(s)) {
        printf("Stack Overflow!\n");
        return;
    }
    s->arr[++(s->top)] = data;
}

int pop(Stack* s) {
    if(isEmpty(s)) {
        printf("Stack Underflow!\n");
        return -1;
    }
    return s->arr[(s->top)--];
}

int peek(Stack* s) {
    if(isEmpty(s)) return -1;
    return s->arr[s->top];
}

// Example Usage
int main() {
    Stack s;
    initStack(&s);
    push(&s, 10);
    push(&s, 20);
    push(&s, 30);
    printf("Top: %d\n", peek(&s));  // 30
    printf("Pop: %d\n", pop(&s));   // 30
    printf("Pop: %d\n", pop(&s));   // 20
    return 0;
}

Implementation 2: Linked List-Based Stack

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node* next;
} Node;

typedef struct {
    Node* top;
} Stack;

void initStack(Stack* s) {
    s->top = NULL;
}

void push(Stack* s, int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = s->top;
    s->top = newNode;
}

int pop(Stack* s) {
    if(s->top == NULL) {
        printf("Stack Empty!\n");
        return -1;
    }
    Node* temp = s->top;
    int data = temp->data;
    s->top = s->top->next;
    free(temp);
    return data;
}

int peek(Stack* s) {
    return (s->top != NULL) ? s->top->data : -1;
}

Structure Diagram (Array Stack)

Index:     0    1    2    3
         +----+----+----+----+
Array:   | 10 | 20 | 30 |    |
         +----+----+----+----+
               ↑
              top = 2

Applications of Stack

ApplicationUse
Function CallCall stack in recursion
Expression EvaluationInfix → Postfix → Evaluate
Parentheses MatchingCheck balanced (), {}, []
Undo OperationIn editors
BacktrackingMaze, N-Queen

Example: Parentheses Matching

int isBalanced(char* exp) {
    Stack s;
    initStack(&s);
    
    for(int i = 0; exp[i] != '\0'; i++) {
        if(exp[i] == '(' || exp[i] == '{' || exp[i] == '[')
            push(&s, exp[i]);
        else if(exp[i] == ')' || exp[i] == '}' || exp[i] == ']') {
            if(isEmpty(&s)) return 0;
            char top = peek(&s);
            if((exp[i] == ')' && top != '(') ||
               (exp[i] == '}' && top != '{') ||
               (exp[i] == ']' && top != '['))
                return 0;
            pop(&s);
        }
    }
    return isEmpty(&s);
}

2. QUEUE

Definition

FIFO (First In, First Out)
First element added is the first one to be removed.


Analogy

A line at a ticket counter: First come, first served.

Front → [A] → [B] → [C] → [D] ← Rear

Basic Operations

OperationDescriptionTime Complexity
enqueue(x)Add x at rearO(1)
dequeue()Remove from frontO(1)
front()View front elementO(1)
rear()View rear elementO(1)
isEmpty()Check if emptyO(1)

Implementation 1: Simple Array Queue (Fixed Size)

#define MAX 100

typedef struct {
    int arr[MAX];
    int front, rear;
} Queue;

void initQueue(Queue* q) {
    q->front = q->rear = -1;
}

int isEmpty(Queue* q) {
    return q->front == -1;
}

int isFull(Queue* q) {
    return q->rear == MAX - 1;
}

void enqueue(Queue* q, int data) {
    if(isFull(q)) {
        printf("Queue Full!\n");
        return;
    }
    if(isEmpty(q))
        q->front = 0;
    q->arr[++(q->rear)] = data;
}

int dequeue(Queue* q) {
    if(isEmpty(q)) {
        printf("Queue Empty!\n");
        return -1;
    }
    int data = q->arr[q->front];
    if(q->front == q->rear)
        q->front = q->rear = -1;
    else
        q->front++;
    return data;
}

Problem: Space wastage after dequeue → Use Circular Queue


Implementation 2: Circular Queue

#define MAX 5

typedef struct {
    int arr[MAX];
    int front, rear;
} CQueue;

void init(CQueue* q) {
    q->front = q->rear = -1;
}

int isFull(CQueue* q) {
    return (q->rear + 1) % MAX == q->front;
}

int isEmpty(CQueue* q) {
    return q->front == -1;
}

void enqueue(CQueue* q, int data) {
    if(isFull(q)) {
        printf("Queue Full!\n");
        return;
    }
    if(isEmpty(q))
        q->front = 0;
    q->rear = (q->rear + 1) % MAX;
    q->arr[q->rear] = data;
}

int dequeue(CQueue* q) {
    if(isEmpty(q)) return -1;
    int data = q->arr[q->front];
    if(q->front == q->rear)
        q->front = q->rear = -1;
    else
        q->front = (q->front + 1) % MAX;
    return data;
}

Circular Queue Diagram

Index:  0   1   2   3   4
      +---+---+---+---+---+
      | D |   | A | B | C |
      +---+---+---+---+---+
          ↑           ↑
        front       rear

Implementation 3: Queue using Linked List

typedef struct Node {
    int data;
    struct Node* next;
} Node;

typedef struct {
    Node *front, *rear;
} Queue;

void initQueue(Queue* q) {
    q->front = q->rear = NULL;
}

void enqueue(Queue* q, int data) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
    
    if(q->rear == NULL) {
        q->front = q->rear = newNode;
        return;
    }
    q->rear->next = newNode;
    q->rear = newNode;
}

int dequeue(Queue* q) {
    if(q->front == NULL) return -1;
    Node* temp = q->front;
    int data = temp->data;
    q->front = q->front->next;
    if(q->front == NULL)
        q->rear = NULL;
    free(temp);
    return data;
}

Applications of Queue

ApplicationUse
CPU SchedulingRound Robin
Breadth-First Search (BFS)Graph traversal
Printer SpoolingPrint jobs
Message QueuesInter-process communication
SimulationBank queue, traffic lights

Comparison: Stack vs Queue

FeatureStackQueue
PrincipleLIFOFIFO
InsertionTop (push)Rear (enqueue)
DeletionTop (pop)Front (dequeue)
AccessOnly topFront & Rear
Use CaseRecursion, UndoBFS, Scheduling

Special Types

1. Deque (Double-Ended Queue)

  • Insert/delete from both ends
  • Can act as Stack or Queue
// Operations: pushFront, pushBack, popFront, popBack

2. Priority Queue

  • Elements have priority
  • Highest priority removed first
  • Implemented using Heap

Summary Table

Data StructureOrderInsertionDeletionUse Case
StackLIFOO(1)O(1)Function calls
Simple QueueFIFOO(1)O(1)Limited space
Circular QueueFIFOO(1)O(1)Efficient space
Linked QueueFIFOO(1)O(1)Dynamic size

Practice Problems

  1. Reverse a string using stack
  2. Implement queue using two stacks
  3. Check palindrome using stack
  4. Implement stack using two queues
  5. Evaluate postfix expression

Key Takeaway:

Stack → For depth and recursion
Queue → For breadth and order preservation


End of Notes