LeetCode:225 .用队列实现栈

目录

前言

题目

思路

接口功能代码实现

第一点

第二点

第三点

源码


前言

小伙伴们大家好,今天我们来了解一篇有关队列和栈的力扣题目:用队列实现栈。

然后接下来我们还会有一篇文章,是用栈实现队列,在这两道题目中,我们都是用栈和队列的一些接口函数去实现,同时我们并不会改变栈和队列原有的结构。

那么对于本文来说,我们关注的就是如何用队列去实现栈,首先我们需要知道的是,队列的特性是“先进先出”,而栈的特性是“先进后出”,所以我们会利用这两个特性去做文章。好的,废话不多讲,我们进入正文。

题目

首先,我们来了解一下力扣上对该题的描述:

如上图所示:我们需要用两个队列去实现一个栈,同时该栈支持基本栈的四种操作,分别为插入,删除,返回栈顶元素以及最后一个判断栈是否为空。

思路

我们知道,如果想实现栈的先进后出:

首先我们需要一个队列 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);
}

那么本文到此就结束啦!如有不对的地方,还请大家指正啊!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值