在之前的文章中,我们讲了栈和队列的代码实现,而栈和队列也可以相互实现。
本文将详解栈和队列的相互实现。
在这里我们用leetcode的题来进行讲解。
用栈实现队列
算法思想
利用栈是先进后出,队列是先进先出的特性,使用两个栈来模拟队列。
我们可以用一个栈来模拟入队操作,另一个栈模拟出队操作,这样就可以实现先进先出。
入队栈只入队,出队栈只用来出队。
如图所示:
数据进入时进入到入队栈中。
当需要出队的时候,将入队栈里的数据都转移到出队栈中。
出队时只需对出队栈进行出栈操作即可完成出队操作。
以上就是算法思想,接下里进行代码实现。
代码实现
leetcode中我们需要手搓一个栈出来,栈的代码实现见链接:https://blog.csdn.net/m0_74089804/article/details/129678048?spm=1001.2014.3001.5501
//下面是用栈实现队列
//先创建一个入队栈,出队栈
typedef struct {
Stack pushst;
Stack popst;
} MyQueue;
//初始化入队出队栈
MyQueue* myQueueCreate() {
MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
Init(&obj->pushst);
Init(&obj->popst);
return obj;
}
//队列的插入即入队栈的插入
void myQueuePush(MyQueue* obj, int x) {
Push(&obj->pushst,x);
}
//队列开头元素,即转移数据后出队栈的栈顶元素
int myQueuePeek(MyQueue* obj) {
//出队栈如果为空则转移全部数据
if(SEmpty(&obj->popst))
{
int size=Size(&obj->pushst);
while(size--)
{
Push(&obj->popst,STop(&obj->pushst));
Pop(&obj->pushst);
}
}
//返回栈顶元素
return STop(&obj->popst);
}
//删除队头元素,即删除转移数据后出队栈的栈顶元素
int myQueuePop(MyQueue* obj) {
//转移数据操作一样,可以直接使用myQueuePeek接口
int front=myQueuePeek(obj);
Pop(&obj->popst);
return front;
}
//判断队列是否为空,入队栈出队栈都为空即队列为空
bool myQueueEmpty(MyQueue* obj) {
return SEmpty(&obj->pushst) && SEmpty(&obj->popst);
}
//队列的销毁,将入队栈出队栈都销毁即可
void myQueueFree(MyQueue* obj) {
Destroy(&obj->pushst);
Destroy(&obj->popst);
free(obj);
obj=NULL;
}
用队列实现栈
算法思想
用队列实现栈,算法思想和用栈实现队列相似,结合栈和队列先入后出,先进先出的特性,我们可以这样实现。
如图所示:
数据进入时先进入到一个队列。
出栈时需要将一个队列的数据转移到另一个队列,留下最后一个元素,即需要出栈的元素。
出栈时直接将剩下的最后一个元素删除即可完成出栈。
当再次需要入栈时,继续往有元素的那个队列插入,再重复以上操作即可。
总体思想就是保持一个队列一直为空,出栈时将数据转移到空队列中,留下一个出栈。
代码实现
代码如下:
leetcode中需要手搓一个队列出来,队列详解请看:https://blog.csdn.net/m0_74089804/article/details/129738965?spm=1001.2014.3001.5501
//下面实现队列模拟栈
//先创建两个队列并进行初始化
typedef struct
{
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
//入栈即在不为空的队列中插入数据
void myStackPush(MyStack* obj, int x) {
//如果q1不为空就在q1插入,反之在q2插入
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
//出栈的操作,先转移数据,再删除
int myStackPop(MyStack* obj) {
//判断哪个是空队列
MyStack* empty=&obj->q1;
MyStack* noempty=&obj->q2;
if(!QueueEmpty(&obj->q1))
{
empty=&obj->q2;
noempty=&obj->q1;
}
//转移数据
while(QueueSize(noempty)>1)//需要剩一个元素来出栈
{
QueuePush(empty,QueueFront(noempty));
QueuePop(noempty);
}
//剩下的那个元素出队列,也就是出栈
int top=QueueFront(noempty);
QueuePop(noempty);
return top;
}
//栈顶元素即不为空队列的队尾元素
int myStackTop(MyStack* obj) {
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
//判断栈是否为空即判断两个队列的size都为空,栈就为空
bool myStackEmpty(MyStack* obj) {
if(QueueSize(&obj->q1)==0 && QueueSize(&obj->q2)==0)
{
return true;
}
else
return false;
}
//栈的销毁即销毁创建的两个队列即可
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
obj=NULL;
}
总结
栈和队列的相互实现还是很考验算法思想,利用好栈和队列的结构特性,即可完成相互实现,前提也是需要熟知栈和队列本身的代码实现。
以上就是本人对栈和队列相互实现的一点见解,不足之处请大佬批评指正,共同进步🌹🌹🌹