项目场景:
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
注意:
你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/implement-stack-using-queues
问题描述
用两个队列实现栈,队列的接口是先进先出,用两个队列,一个队列存数据,一个队列为空,
队列从队头出数据,进入空队列,出数据循环,直到非空队列只剩一个元素,出这个元素,此时
实现了栈的后进先出的接口。
原因分析:
1.队列的实现接口包括:队列的定义,初始化,读取队头数据,读取队尾数据,入队,出队,判断队列是否为空,销毁队列
2.栈的实现接口包括:栈的定义,初始化,出栈,入栈,销毁栈,判断栈是否为空,销毁栈
解决方案:
1.定义一个栈:用两个队列(具体队列的操作详见之前博客)
2.实现栈的初始化:两个队列的初始化
typedef struct
{
Queue q1;
Queue q2;
}Mystack;
MyStack * myStackCreate*()
{
MyStack * mystack = (MyStack *)malloc(sizeof(MyStack));
QueueInit(mystack->q1)
QueueInit(mystack->q2)
return mystack;
}
3.判断栈是否为空:判断两个队列是否为空
bool myStackEmpty(MyStack * obj)
{
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
4.入栈:哪个队列为空,入哪个队列
void myStackPush(MyStack *obj,int x)
{
assert(obj);
if(!QueueEmpty(&obj->q1)
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
5.出栈:队列中有数据,导入空队列,直到只剩下一个,出队列-->实现出栈
int myStackPop(MyStack * obj)
{
assert(obj);
//不知道哪个是空队列,先假设
Queue * emptyQ = &obj->q1;
Queue * nonemptyQ = &obj->q2;
if(!QueueEmpty(&obj->q1)
{
emptyQ = &obj->q2;
nonemptyQ = &obj->q1;
}
while(QueueSize(nonemptyQ) >1)
{
//从非空队头出数据,放到空队列中
QueuePush(emptyQ,QueueFront(nonemptyQ));
//删除非空中的元素
QueuePop(nonemptyQ)
}
//此时非空队列中只剩下一个元素,就是栈顶元素
int top = QueueFront(nonemptyQ);
//栈顶元素取到之后,此队列变空
QueuePop(nonemptyQ)
return top;
}
6.读取栈顶数据:一直保持一个队伍存数据,一个队伍为空,现在读取栈顶数据不需要删除,即读取队列的尾部数据
int MyStackTop(MyStack * obj)
{
if(!QueueEmpty(&obj->q1)
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
6.销毁栈:先销毁栈中队列,再销毁栈的结构体
void myStackFree(MyStack * obj)
{
QueueDestroy(&obj->q1)'
QueueDestroy(&obj->q2);
free(obj);
obj=NULL;
}