在数据结构与算法中,栈和队列是两个重要的基础结构。它们的特性不同但却有趣地可以相互模拟实现,本文将通过C语言来探讨如何用栈实现队列,以及如何用队列实现栈。
一、栈实现队列
用两个栈来实现队列的核心思想是:
- 一个栈(输入栈)用于插入元素;
- 另一个栈(输出栈)用于移除元素。
当需要从队列中取元素时,如果输出栈为空,则将输入栈的所有元素依次弹出并压入输出栈。
核心步骤
- 入队操作:将新元素压入输入栈。
- 出队操作:如果输出栈为空,则将输入栈的元素逐个弹出并压入输出栈;然后从输出栈弹出栈顶元素。
代码如下
#include <stdio.h>
#include <stdlib.h>
// 定义栈结构
typedef struct {
int *data;
int top;
int capacity;
} Stack;
// 创建栈
Stack* createStack(int capacity) {
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->data = (int*)malloc(sizeof(int) * capacity);
stack->top = -1;
stack->capacity = capacity;
return stack;
}
// 判断栈是否为空
int isEmpty(Stack* stack) {
return stack->top == -1;
}
// 入栈
void push(Stack* stack, int x) {
stack->data[++stack->top] = x;
}
// 出栈
int pop(Stack* stack) {
return stack->data[stack->top--];
}
// 获取栈顶元素
int top(Stack* stack) {
return stack->data[stack->top];
}
// 定义队列结构
typedef struct {
Stack *inStack;
Stack *outStack;
} Queue;
// 创建队列
Queue* createQueue(int capacity) {
Queue* queue = (Queue*)malloc(sizeof(Queue));
queue->inStack = createStack(capacity);
queue->outStack = createStack(capacity);
return queue;
}
// 入队操作
void enqueue(Queue* queue, int x) {
push(queue->inStack, x);
}
// 出队操作
int dequeue(Queue* queue) {
if (isEmpty(queue->outStack)) {
while (!isEmpty(queue->inStack)) {
push(queue->outStack, pop(queue->inStack));
}
}
if (!isEmpty(queue->outStack)) {
return pop(queue->outStack);
}
printf("Queue is empty!\n");
return -1;
}
// 获取队头元素
int front(Queue* queue) {
if (isEmpty(queue->outStack)) {
while (!isEmpty(queue->inStack)) {
push(queue->outStack, pop(queue->inStack));
}
}
if (!isEmpty(queue->outStack)) {
return top(queue->outStack);
}
printf("Queue is empty!\n");
return -1;
}
// 测试
int main() {
Queue* queue = createQueue(10);
enqueue(queue, 1);
enqueue(queue, 2);
enqueue(queue, 3);
printf("Dequeue: %d\n", dequeue(queue)); // 输出 1
printf("Front: %d\n", front(queue)); // 输出 2
enqueue(queue, 4);
printf("Dequeue: %d\n", dequeue(queue)); // 输出 2
printf("Dequeue: %d\n", dequeue(queue)); // 输出 3
return 0;
}
二、队列实现栈
用两个队列来实现栈的核心思想是:
- 始终保持一个队列为空,另一个队列存储数据;
- 每次插入新元素时,通过两个队列的切换模拟栈的特性。
核心步骤
- 入栈操作:将元素加入非空队列。
- 出栈操作:将非空队列中除最后一个元素外的所有元素依次移入另一个空队列,然后删除最后一个元素。
代码如下
#include <stdio.h>
#include <stdlib.h>
// 定义队列结构
typedef struct {
int *data;
int front, rear;
int size, capacity;
} Queue;
// 创建队列
Queue* createQueue(int capacity) {
Queue* queue = (Queue*)malloc(sizeof(Queue));
queue->data = (int*)malloc(sizeof(int) * capacity);
queue->front = queue->rear = -1;
queue->size = 0;
queue->capacity = capacity;
return queue;
}
// 判断队列是否为空
int isEmptyQueue(Queue* queue) {
return queue->size == 0;
}
// 入队
void enqueueQueue(Queue* queue, int x) {
queue->rear = (queue->rear + 1) % queue->capacity;
queue->data[queue->rear] = x;
queue->size++;
}
// 出队
int dequeueQueue(Queue* queue) {
int item = queue->data[queue->front];
queue->front = (queue->front + 1) % queue->capacity;
queue->size--;
return item;
}
// 定义栈结构
typedef struct {
Queue *q1, *q2;
} Stack;
// 创建栈
Stack* createStackWithQueues(int capacity) {
Stack* stack = (Stack*)malloc(sizeof(Stack));
stack->q1 = createQueue(capacity);
stack->q2 = createQueue(capacity);
return stack;
}
// 入栈操作
void pushWithQueues(Stack* stack, int x) {
enqueueQueue(stack->q1, x);
}
// 出栈操作
int popWithQueues(Stack* stack) {
if (isEmptyQueue(stack->q1)) {
printf("Stack is empty!\n");
return -1;
}
while (stack->q1->size > 1) {
enqueueQueue(stack->q2, dequeueQueue(stack->q1));
}
int item = dequeueQueue(stack->q1);
Queue* temp = stack->q1;
stack->q1 = stack->q2;
stack->q2 = temp;
return item;
}
// 测试
int main() {
Stack* stack = createStackWithQueues(10);
pushWithQueues(stack, 1);
pushWithQueues(stack, 2);
pushWithQueues(stack, 3);
printf("Pop: %d\n", popWithQueues(stack)); // 输出 3
printf("Pop: %d\n", popWithQueues(stack)); // 输出 2
return 0;
}
总结一下
- 栈实现队列依赖两个栈,一个负责输入,一个负责输出。
- 队列实现栈依赖两个队列,借助队列的轮换来模拟栈的特性。
- 代码实现中应注意边界情况,比如栈或队列为空的处理。