How to implement a queue using two stacks in C

1 Answer

0 votes
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

/*
    Queue implemented using two stacks in C.

    Concept:
    - stack_in  : receives new elements (enqueue)
    - stack_out : serves elements in correct queue order (dequeue)

    When stack_out is empty and we need to dequeue or peek:
    - Move all elements from stack_in to stack_out
      This reverses the order, making the oldest element accessible.

    This design provides amortized O(1) operations and keeps the code simple.
*/

/* -------------------- Stack Implementation -------------------- */

typedef struct {
    int *data;      // dynamic array
    size_t size;    // current number of elements
    size_t capacity;// allocated capacity
} Stack;

// Create a new stack
Stack *stack_create(size_t initial_capacity) {
    Stack *s = malloc(sizeof(Stack));
    if (!s) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    s->data = malloc(initial_capacity * sizeof(int));
    if (!s->data) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    s->size = 0;
    s->capacity = initial_capacity;
    return s;
}

// Push a value onto the stack
void stack_push(Stack *s, int value) {
    if (s->size == s->capacity) {
        // grow capacity
        s->capacity *= 2;
        s->data = realloc(s->data, s->capacity * sizeof(int));
        if (!s->data) {
            fprintf(stderr, "Memory allocation failed\n");
            exit(EXIT_FAILURE);
        }
    }
    s->data[s->size++] = value;
}

// Pop a value from the stack
int stack_pop(Stack *s) {
    if (s->size == 0) {
        fprintf(stderr, "Stack underflow\n");
        exit(EXIT_FAILURE);
    }
    return s->data[--s->size];
}

// Peek at the top value
int stack_top(const Stack *s) {
    if (s->size == 0) {
        fprintf(stderr, "Stack is empty\n");
        exit(EXIT_FAILURE);
    }
    return s->data[s->size - 1];
}

// Check if stack is empty
bool stack_empty(const Stack *s) {
    return s->size == 0;
}

// Destroy stack
void stack_destroy(Stack *s) {
    free(s->data);
    free(s);
}

/* -------------------- Queue Using Two Stacks -------------------- */

typedef struct {
    Stack *stack_in;   // receives new elements
    Stack *stack_out;  // serves elements in queue order
} Queue;

// Create queue
Queue *queue_create(void) {
    Queue *q = malloc(sizeof(Queue));
    if (!q) {
        fprintf(stderr, "Memory allocation failed\n");
        exit(EXIT_FAILURE);
    }

    q->stack_in  = stack_create(4);
    q->stack_out = stack_create(4);
    return q;
}

// Move elements from stack_in to stack_out when needed
void transfer_if_needed(Queue *q) {
    if (stack_empty(q->stack_out)) {
        while (!stack_empty(q->stack_in)) {
            int value = stack_pop(q->stack_in);
            stack_push(q->stack_out, value);
        }
    }
}

// Enqueue
void enqueue(Queue *q, int value) {
    stack_push(q->stack_in, value);
}

// Dequeue
int dequeue(Queue *q) {
    transfer_if_needed(q);
    if (stack_empty(q->stack_out)) {
        fprintf(stderr, "Queue is empty\n");
        exit(EXIT_FAILURE);
    }
    return stack_pop(q->stack_out);
}

// Front
int front(Queue *q) {
    transfer_if_needed(q);
    if (stack_empty(q->stack_out)) {
        fprintf(stderr, "Queue is empty\n");
        exit(EXIT_FAILURE);
    }
    return stack_top(q->stack_out);
}

// Check if queue is empty
bool queue_empty(Queue *q) {
    return stack_empty(q->stack_in) && stack_empty(q->stack_out);
}

// Destroy queue
void queue_destroy(Queue *q) {
    stack_destroy(q->stack_in);
    stack_destroy(q->stack_out);
    free(q);
}

/* -------------------- Demonstration -------------------- */

int main(void) {
    Queue *q = queue_create();

    // stack_in
    enqueue(q, 10);
    enqueue(q, 20);
    enqueue(q, 30);

    printf("Front element: %d\n", front(q));   // 10 // stack_out

    printf("Dequeued: %d\n", dequeue(q));      // 10 // stack_out
    printf("Dequeued: %d\n", dequeue(q));      // 20

    enqueue(q, 40);

    printf("Front element: %d\n", front(q));   // 30

    printf("Dequeued: %d\n", dequeue(q));      // 30
    printf("Dequeued: %d\n", dequeue(q));      // 40

    printf("Queue empty: %s\n", queue_empty(q) ? "true" : "false");

    queue_destroy(q);
  
    return 0;
}



/*
run:

Front element: 10
Dequeued: 10
Dequeued: 20
Front element: 30
Dequeued: 30
Dequeued: 40
Queue empty: true

*/

 



answered Sep 4 by avibootz
...