- 用队列实现栈- LeetCode链接
- 提示
用两个队列实现栈,只要保持任意一个队列为空即可,下文以Queue2为空时为例。另一种情况也就是Queue1为空时进行相同操作,这里不再赘述。
本例忽略队列的实现,仅演示队列的调用和栈的实现。
- 思路
假设入栈n个元素。由于栈是后进先出,队列是先进先出,所以可以用Queue1模拟入栈操作,当需要模拟出栈操作时,就把前面已经入Queue1的前n-1个元素入到Queue2里,再把Queue1最后一个元素出队列,就模拟成了出栈操作
如下图:由于紫色是最后进栈的,所以它要先出栈。先把Queue1里的绿红黄入到Queue2,Queue1剩下紫色,这时候对Queue1进行出队列操作就完成了出栈操作。当此时需要再出一个黄色方块元素时,就按相同操作把元素入到Queue1里完成相同操作即可。
- 注意
本例在执行销毁栈操作时,不能直接通过释放结构体指针的方式free(obj),原因是实现队列的空间是独立申请开辟的,而建立栈时,创建的结构体指针指向的那块空间是另外独立开辟的,所以如果直接释放掉结构体指针obj,会导致队列的内存空间无法释放,若队列里本就还有数据,里面的空间和数据都无法销毁。
这是一种解耦的方式,因为实现这个栈只需要调用队列的接口,完全不用关心队列是如何实现的。
-
图解
-
代码实现
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)
{
//随机选不为空的队列把数据插入
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
//出栈
int myStackPop(MyStack* obj)
{
//默认Queue1为空,判断不为空则Queue2为空
Queue* empty = &obj->q1;
Queue* nonempty = &obj->q2;
if(!QueueEmpty(&obj->q1))
{
empty = &obj->q2;
nonempty = &obj->q1;
}
//把队列元素出到只剩最后一个
while(QueueSize(nonempty) > 1)
{
//前n-1个出队列的元素都入到另一个空队列里
QueuePush(empty,QueueFront(nonempty));
QueuePop(nonempty);
}
//要求是“移除并返回栈顶元素”所以要保存返回
int top = QueueFront(nonempty);
QueuePop(nonempty);
return top;
}
//返回栈顶元素
int myStackTop(MyStack* obj)
{
//栈顶元素是队列尾元素Back
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
//栈判空
bool myStackEmpty(MyStack* obj)
{
//要求是两个队列都为空,栈才为空
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
//销毁栈
void myStackFree(MyStack* obj)
{
//q1q2指向的队列空间也要回收
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
//回收栈申请的空间
free(obj);
}