目录
前言
小伙伴们大家好,今天我们来了解一篇有关队列和栈的力扣题目:用队列实现栈。
然后接下来我们还会有一篇文章,是用栈实现队列,在这两道题目中,我们都是用栈和队列的一些接口函数去实现,同时我们并不会改变栈和队列原有的结构。
那么对于本文来说,我们关注的就是如何用队列去实现栈,首先我们需要知道的是,队列的特性是“先进先出”,而栈的特性是“先进后出”,所以我们会利用这两个特性去做文章。好的,废话不多讲,我们进入正文。
题目
首先,我们来了解一下力扣上对该题的描述:
如上图所示:我们需要用两个队列去实现一个栈,同时该栈支持基本栈的四种操作,分别为插入,删除,返回栈顶元素以及最后一个判断栈是否为空。
思路
我们知道,如果想实现栈的先进后出:
首先我们需要一个队列 q1 来入队列,然后另一个队列q2 保持空的状态,此时 q1 就相当于是入栈操作了,因为我们可以将队尾当做栈顶,而将队首当做栈底。如下图所示:
直到,我们需要出队列的时候,我们可以将 q1 队列中的元素依次出队列,然后依次入队列到 q2 中,直到最后一个元素,此时将该元素出队列,返回,就实现了栈的出栈。如下图所示:
那么,下一次如果我们想早次入栈的话,只需要在不为空的一个队列上继续增加即可。如果需要出栈,因为现在又有一个队列是空着的,所以我们只需要再次执行上面的步骤即可。
还有需要实现的函数有,返回栈顶元素以及判断栈是否为空。
那么我们发现,其实如果是找栈顶元素的话,其实只需要将不为空的那个队列的队尾元素返回即可。
然后对于判断栈是否为空的接口,只需要调用队列的判空函数,然后当两个队列同时为空时,表示当前栈为空。
接口功能代码实现
当我们有了以上思路之后,其实代码主要就是一些接口套用实现:
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
//将两个队列实现初始化
MyStack*st=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&st->q1);
QueueInit(&st->q2);
return st;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q1,x);
}
}
int myStackPop(MyStack* obj) {
Queue*emptyQ=&obj->q1;
Queue*noneemptyQ=&obj->q2;
if(!QueueEmpty(&obj->q1))
{
emptyQ=&obj->q2;
noneemptyQ=&obj->q1;
}
while(QueueSize(noneemptyQ)>1)
{
QueuePush(emptyQ,QueueFront(noneemptyQ));
QueuePop(noneemptyQ);
}
int ret=QueueFront(noneemptyQ);
QueuePop(noneemptyQ);
return ret;
}
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);
}
对于以上代码来说,我们有如下解释:
第一点
因为我们用队列实现的栈,用了两个队列,所以这里我们将这两个队列集中在一个结构体中,所以我们需要给该结构体分配一个空间,除此之外,每个新增的元素的空间都在队列的接口中已经实现了,这里我们只需要考虑这两个队列的空间,而且只需要开辟一次就可以了。
然后我们就需要对其进行初始化,因为需要修改结构体内容,所以需要传递指针。
第二点
在进行删除操作时,首先我们假设 q1 是空队列,q2 是非空队列。之后我们进行一个判断,如果不是,我们则将其互换。这样后面就不用判断,直接进行出栈的操作了。
第三点
对于判断是否为空的接口,其返回值是 bool 值,所以我们只需要调用队列判空的函数,然后确定两个都是空的时候,此时才表示该栈为空。
最后在释放的时候,同样我们是调用原队列中的释放函数,但是这里一定不要忘记,在最开始申请的那个两个队列的结构体,如果这里我们将两个队列分别释放了之后,没有将该结构体释放,此时就造成了野指针的问题。
好的,那么总结来说,这里实现栈我们直接用数组是可以实现的,但是这里就是单纯为了大家去实际体验接口函数的嵌套实现。
源码
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
//初始化栈
void StackInit(ST*ps);
//销毁
void StackDestroy(ST*ps);
//插入
void StackPush(ST*ps,STDataType x);
//删除
void StackPop(ST*ps);
//取栈顶的数据
STDataType StackTop(ST* ps);
//栈里面有多少个数据
int StackSize(ST* ps);
//判断栈是否满
bool StackEmpty(ST* ps);
//初始化栈
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
//销毁
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->top = ps->capacity = 0;
}
//插入
void StackPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
int newcapacity = (ps->capacity == 0) ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a,newcapacity*sizeof(STDataType));
ps->capacity = newcapacity;
ps->a = tmp;
}
//插入
ps->a[ps->top] = x;
ps->top++;
}
//删除
void StackPop(ST* ps)
{
assert(ps && ps->top > 0);
assert(!StackEmpty(ps));
ps->top--;
}
//取栈顶的数据
STDataType StackTop(ST* ps)
{
assert(ps && ps->top > 0);
assert(!StackEmpty(ps));
return ps->a[ps->top-1];
}
//栈里面有多少个数据
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
//判断栈是否为空
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
typedef struct {
ST pushST;
ST popST;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue *pq=(MyQueue*)malloc(sizeof(MyQueue));
StackInit(&pq->pushST);
StackInit(&pq->popST);
return pq;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->pushST,x);
}
int myQueuePop(MyQueue* obj) {
if(StackEmpty(&obj->popST))
{
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
int front=StackTop(&obj->popST);
StackPop(&obj->popST);
return front;
}
int myQueuePeek(MyQueue* obj) {
//如果pushST为空怎么办,不应该是先判断吗
//为什么这里没有判断
if(StackEmpty(&obj->popST))
{
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
return StackTop(&obj->popST);
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->popST)&&StackEmpty(&obj->pushST);
}
void myQueueFree(MyQueue* obj) {
StackDestroy(&obj->pushST);
StackDestroy(&obj->popST);
free(obj);
}
那么本文到此就结束啦!如有不对的地方,还请大家指正啊!