
🔥小龙报:个人主页
🎬作者简介:C++研发,嵌入式,机器人等方向学习者
❄️个人专栏:《C语言》《【初阶】数据结构与算法》
✨ 永远相信美好的事情即将发生

文章目录
- 前言
- 一、用栈实现队列
-
- 1.1题目
- [1.2 算法原理](#1.2 算法原理)
- [1.3 代码](#1.3 代码)
- 二、用队列实现栈
-
- [2.1 题目](#2.1 题目)
- [2.2 算法原理](#2.2 算法原理)
- [2.3 代码](#2.3 代码)
- 三、设计循环队列
-
- [3.1 题目](#3.1 题目)
- [3.2 算法原理](#3.2 算法原理)
- [3.3 代码](#3.3 代码)
- 总结与每日励志
前言
栈和队列作为数据结构的基础线性表,核心差异在于 "先进后出" 与 "先进先出" 的特性,但实际开发中常需要灵活转换二者的行为模式。本文聚焦栈和队列的经典综合应用:用栈模拟队列、用队列实现栈,以及高频面试考点 ------ 设计循环队列。通过拆解算法原理、实现完整代码,帮助读者吃透底层逻辑,掌握线性表的灵活运用思路。
一、用栈实现队列
1.1题目
链接:用栈实现队列

1.2 算法原理
首先就是要先定义栈结构创建两个栈:一个栈专门入队 + 一个栈专门出队;
出队:先检查出队栈是否有元素,如果有就直接出队,如果没有就把入队栈的元素全部push到出队栈,然后出队栈弹出栈顶元素即可;
入队:直接入入队栈即可
1.3 代码
typedef int StkDataType;
typedef struct stack
{
StkDataType* a; //数组
int top;
int capacity;
}stack;
//初始化
void StkInit(stack* stk)
{
stk->a = NULL;
stk->top = 0;
stk->capacity = 0;
}
//销毁
void StkDestory(stack* stk)
{
free(stk->a);
stk->a = NULL;
stk->top = 0;
stk->capacity = 0;
}
//插入
void StkPush(stack* stk, StkDataType x)
{
assert(stk);
if (stk->top == stk->capacity)
{
int newcapacity = stk->capacity == 0 ? 4 : 2 * stk->capacity;
StkDataType* temp = (StkDataType*)realloc(stk->a, newcapacity * sizeof(StkDataType));
if (temp == NULL)
{
printf("fail!\n");
exit(-1);
}
stk->a = temp;
stk->capacity = newcapacity;
}
stk->a[stk->top++] = x;
}
//弹出
void StkPop(stack* stk)
{
assert(stk && stk->top > 0);
stk->top--;
}
//大小
int StkSize(stack* stk)
{
return stk->top;
}
//栈顶
StkDataType StkTop(stack* stk)
{
assert(stk && stk->top > 0);
return stk->a[stk->top - 1];
}
//判空
bool StkEmpty(stack* stk)
{
assert(stk);
return stk->top == 0;
}
typedef struct
{
stack stk1; //入队
stack stk2; //出队
} MyQueue;
MyQueue* myQueueCreate()
{
MyQueue* psk = (MyQueue*)malloc(sizeof(MyQueue));
StkInit(&(psk->stk1));
StkInit(&(psk->stk2));
return psk;
}
void myQueuePush(MyQueue* obj, int x)
{
StkPush(&(obj->stk1),x);
}
int myQueuePop(MyQueue* obj)
{
//出队栈不为空
if(!StkEmpty(&(obj->stk2)))
{
int ret = StkTop(&(obj->stk2));
StkPop(&(obj->stk2));
return ret;
}
else
{
int size = StkSize(&(obj->stk1));
while(size--)
{
int top = StkTop(&(obj->stk1));
StkPush(&(obj->stk2),top);
StkPop(&(obj->stk1));
}
int ret = StkTop(&(obj->stk2));
StkPop(&(obj->stk2));
return ret;
}
}
int myQueuePeek(MyQueue* obj)
{
//出队栈不为空
if(!StkEmpty(&(obj->stk2)))
{
int ret = StkTop(&(obj->stk2));
return ret;
}
else
{
int size = StkSize(&(obj->stk1));
while(size--)
{
int top = StkTop(&(obj->stk1));
StkPush(&(obj->stk2),top);
StkPop(&(obj->stk1));
}
int ret = StkTop(&(obj->stk2));
return ret;
}
}
bool myQueueEmpty(MyQueue* obj)
{
return (StkEmpty(&(obj->stk1)) && StkEmpty(&(obj->stk2)));
}
void myQueueFree(MyQueue* obj)
{
StkDestory(&(obj->stk1));
StkDestory(&(obj->stk2));
free(obj);
obj = NULL;
}
二、用队列实现栈
2.1 题目
链接:用队列实现栈
2.2 算法原理
首先就是要先定义队列结构创建两个队列:并保持一个队列一定为空
出栈:哪个栈不为空元素入哪个,出栈时把不为空的队列中的size - 1个元素入到为空的队列中,那么那么原本不为空的队列最后一个元素即为栈顶元素
2.3 代码
typedef int QueueDataType;
typedef struct QueueNode
{
QueueDataType val;
struct QueueNode* next;
}QNode;
//定义头尾指针结构体
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;
}Queue;
//初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
//销毁
void QueueDestory(Queue* pq)
{
assert(pq);
QNode* cur = pq->phead;
while (cur)
{
QNode* temp = cur->next;
free(cur);
cur = temp;
}
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
//添加
void QueuePush(Queue* pq, QueueDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
printf("开辟失败!");
return;
}
newnode->val = x;
newnode->next = NULL;
//尾插
if (pq->ptail == NULL)
pq->phead = pq->ptail = newnode;
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
//删除
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->size > 0);
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
pq->size--;
}
//队头
QueueDataType QueueFront(Queue* pq)
{
assert(pq);
assert(pq->size > 0);
return pq->phead->val;
}
//队尾
QueueDataType QueueBack(Queue* pq)
{
assert(pq);
assert(pq->size > 0);
return pq->ptail->val;
}
//判空
bool QueueIsEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
//队列大小
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
typedef struct
{
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate()
{
MyStack* ret = (MyStack*)malloc(sizeof(MyStack));
QueueInit(&(ret->q1));
QueueInit((&ret->q2));
return ret;
}
void myStackPush(MyStack* obj, int x)
{
if(!QueueIsEmpty(&obj->q1))
QueuePush(&obj->q1,x);
else
QueuePush((&obj->q2),x);
}
int myStackPop(MyStack* obj)
{
//判断谁为空队列 --- 假设法
Queue* empty = &obj->q1;
Queue* noempty = &obj->q2;
if(!QueueIsEmpty(&obj->q1))
{
noempty = &obj->q1;
empty = &obj->q2;
}
//让非空队列的前n-1个出队
while(noempty->size > 1)
{
QueuePush(empty,QueueFront(noempty));
QueuePop(noempty);
}
int ret = QueueFront(noempty);
QueuePop(noempty);
return ret;
}
int myStackTop(MyStack* obj)
{
if(!QueueIsEmpty(&(obj->q1)))
return QueueBack(&obj->q1);
else
return QueueBack(&obj->q2);
}
bool myStackEmpty(MyStack* obj)
{
return (QueueIsEmpty(&obj->q1) && QueueIsEmpty(&obj->q2));
}
void myStackFree(MyStack* obj)
{
QueueDestory(&obj->q1);
QueueDestory(&obj->q2);
free(obj);
obj = NULL;
}
三、设计循环队列
3.1 题目
链接:设计循环队列

3.2 算法原理
循环的关键是取模。
1.如何解决队列是否满?多开一个空间
定义两个变量head,tail,其中tail指向队尾的下一个位置
3.3 代码
typedef struct
{
int* data;
int head;
int tail;
int k;
} MyCircularQueue;
bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->data = (int*)malloc((k + 1) * sizeof(int));
obj->head = obj->tail = 0;
obj->k = k;
return obj;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
return false;
else
{
obj->data[obj->tail] = value;
obj->tail++;
obj->tail %= (obj->k + 1);
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return false;
else
{
obj->head++;
obj->head %= (obj->k + 1);
return true;
}
}
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return -1;
else
return obj->data[obj->head];
}
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
return -1;
else
return obj->tail == 0 ? obj->data[obj->k]:obj->data[obj->tail - 1];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->head == obj->tail;
}
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return (obj->tail + 1) % (obj->k + 1) == obj->head;
}
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->data);
obj->data = NULL;
free(obj);
}
总结与每日励志
✨ 本文通过三个经典案例,拆解了栈与队列的核心转换逻辑:双栈模拟队列靠 "入队栈 + 出队栈" 分流操作,双队列实现栈靠 "空队列中转" 定位栈顶,循环队列则通过 "多开空间 + 取模" 解决首尾衔接问题。这些场景本质是对 "先进先出 / 后进先出" 特性的灵活重构。学习数据结构没有捷径,坚持拆解每一个逻辑细节,终能把复杂问题拆解为可落地的代码,永远相信坚持的力量!
