注:前两篇博客已经具体实现了栈和队列,本篇博客在需要用到队列的地方会直接使用它的操作函数。
目录
用队列实现栈
思路
示例
代码实现
入栈
出栈
获取栈顶元素
检测栈是否为空
销毁栈
全部代码
测试用例
要求:仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
队列是一种先入先出的数据结构,而栈是一种后入先出的数据结构,那么如何用两个队列实现栈呢?我们知道,这两种数据结构入数据的方式是相同的,那么只需用队列先入先出的逻辑来实现栈后入先出的逻辑即可。
由于入数据的方式相同,最开始我们可以将数据先入到其中一个队列。出数据时,由于需要出队尾的第一个元素,我们可以将这个非空队列(现存有数据的队列)中除队尾元素外的所有元素都倒入到另一个空队列(现未存数据的队列)中,这样,需要出的元素就到了队列的首位,然后直接出这个元素即可,之后入数据入到有元素的队列。
下面是出数据 5 的示例,先将数据1,2,3,4倒入到最初为空队列的 emptyQ 中,然后出最初为nonemptyQ队列中的剩下一个元素。这样便利用两个队列的性质实现了栈的性质。
注:这里的 nonemptyQ 和 emptyQ 只是一开始对这两个队列做的标识,方便我们在实际操作中使用这两个队列。
我们可以使用的队列操作有:QueueInit、QueueDestroy、QueuePush、QueuePop、QueueFront、QueueBack、QueueSize、QueueEmpty。
我们先创建好需要用两个队列实现的栈:
(假设这里的Queue是我们已经定义好的队列)
typedef struct
{
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate()
{
MyStack* ps = (MyStack*)malloc(sizeof(MyStack));
if(ps == NULL)
{
printf("malloc fail\n");
exit(-1);
}
QueueInit(&ps->q1);
QueueInit(&ps->q2);
return ps;
}
下面给出需要我们实现的接口:
//将元素 x 压入栈顶
void myStackPush(MyStack* obj, int x);
//移除并返回栈顶元素
int myStackPop(MyStack* obj);
//返回栈顶元素
int myStackTop(MyStack* obj);
//如果栈是空的,返回 true ;否则,返回 false
bool myStackEmpty(MyStack* obj);
//销毁栈
void myStackFree(MyStack* obj);
将需要入栈的元素入到其中不为空的队列中,当两个队列都为空时,元素入到其中一个队列即可。
void myStackPush(MyStack* obj, int x)
{
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1, x);
}
else
{
QueuePush(&obj->q2, x);
}
}
将非空队列中除最后一个外的其它元素倒入到另一个队列中,保存剩下元素作为返回值后出队列。
int myStackPop(MyStack* 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;
}
返回非空队列中队尾的元素即可。
int myStackTop(MyStack* obj)
{
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)
{
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
typedef struct
{
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate()
{
MyStack* ps = (MyStack*)malloc(sizeof(MyStack));
if(ps == NULL)
{
printf("malloc fail\n");
exit(-1);
}
QueueInit(&ps->q1);
QueueInit(&ps->q2);
return ps;
}
void myStackPush(MyStack* obj, int x)
{
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1, x);
}
else
{
QueuePush(&obj->q2, x);
}
}
int myStackPop(MyStack* 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;
}
int myStackTop(MyStack* obj)
{
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)
{
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
void TestMyStack()
{
MyStack* ST = myStackCreate();
myStackPush(ST, 1);
myStackPush(ST, 2);
myStackPush(ST, 3);
myStackPush(ST, 4);
myStackPush(ST, 5);
printf("%d\n", myStackTop(ST));
printf("%d\n", myStackPop(ST));
printf("%d\n", myStackPop(ST));
printf("%d\n", myStackTop(ST));
while (!myStackEmpty(ST))
{
printf("%d ", myStackPop(ST));
}
printf("\n");
myStackFree(ST);
}
int main()
{
TestMyStack();
return 0;
}