力扣(leetcode)-用队列实现栈-c语言-数据结构oj题

目录

a.题目链接

b.题目

一、题意解析

a. 需要明白几点:

*核心思想:一个队列用于存数据,另一个队列用于在非空队列需要出队尾数据时,存其他的数据。

图示:

二、每个函数实现的具体讲解

1.定义两个队列结构体

2.用队列实现栈的初始化

3.用队列实现入栈

4.出栈并返回栈顶元素

5.用队列实现返回栈顶元素

6.用队列实现栈空的判断

7.用队列实现栈的销毁

8.测试用例

三、完整代码


题目的所有代码在文章末尾处

a.题目链接

有效的括号icon-default.png?t=N7T8https://leetcode.cn/problems/implement-stack-using-queues/description/

b.题目

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。
  • int pop() 移除并返回栈顶元素。
  • int top() 返回栈顶元素。
  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
  • 注意:

  • 你只能使用队列的标准操作 —— 也就是 push to backpeek/pop from frontsize 和 is empty 这些操作。
  • 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
  • 1 <= x <= 9
  • 最多调用100 次 pushpoptop 和 empty
  • 每次调用 pop 和 top 都保证栈不为空

题目所给代码:

typedef struct {

   

} MyStack;


 

MyStack* myStackCreate() {

   

}

void myStackPush(MyStack* obj, int x) {

   

}

int myStackPop(MyStack* obj) {

   

}

int myStackTop(MyStack* obj) {

   

}

bool myStackEmpty(MyStack* obj) {

   

}

void myStackFree(MyStack* obj) {

   

}

一、题意解析

a. 需要明白几点:

1.队列是什么?

2.栈是什么?

3.它们之间的区别是什么?

具体可见主页博客:栈和队列的概念与实现

通过清楚他们的概念与各种区别,现在我们可以开始做题了

b.思路

队列是先进先出,而栈是先进后出,要想用队列实现栈肯定需要将队的顺序进行一个调转。

队列删除是删除的队列最先中最早进去的元素,队列插入是从队尾入队;

栈删除是删除的是栈中最后进去的那个元素,即栈的栈顶元素,插入是从栈顶插入。

示例:

输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]

解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False

*核心思想:一个队列用于存数据,另一个队列用于在非空队列需要出队尾数据时,存其他的数据。

图示:

在队列a只剩一个元素时,即原本的队尾元素,这个元素便是我们要取的 栈顶元素,为了实现pop的功能:删除元素并返回栈顶元素,因此要将此数据先保存,再删除,方便之后的返回。

二、每个函数实现的具体讲解

1.定义两个队列结构体

typedef struct {  

    Queue q1;

    Queue q2;

} MyStack;

1.q1,q2用于操作结构体

2.用队列实现栈的初始化

MyStack* myStackCreate() {

    MyStack* pst = (MyStack*)malloc(sizeof(MyStack));

    QueueInit(&pst->q1);

    QueueInit(&pst->q2);

    return pst;

}

a.Mystact st;return &pst;为什么不能这样写。

b.因为Mystact st是一个局部变量,出作用域及销毁。

c.能不能返回一个局部变量的地址?

当然不行。会形成野指针,因此要malloc, 出作用域不会销毁。

3.用队列实现入栈

void myStackPush(MyStack* obj, int x) {

    if (!QueueEmpty(&obj->q1))//谁不为空就进谁

    {

        QueuePush(&obj->q1, x);

    }

    else

    {

        QueuePush(&obj->q2, x);

    }

}

4.出栈并返回栈顶元素

int myStackPop(MyStack* obj) {   

    Queue* emptyq = &obj->q1;    //假设第一个队列是空的

    Queue* nonemptyq = &obj->q2;

    if (!QueueEmpty(&obj->q1))//如果不是空的就交换

    {

        emptyq = &obj->q2;

        nonemptyq = &obj->q1;

    }

    //非空队列前n-1个导入空队列,剩下的最后一个就是要取的栈顶元素,可以看前面的图再理解

    while (QueueSize(nonemptyq) > 1)

    {

        QueuePush(emptyq, QueueFront(nonemptyq));

        QueuePop(nonemptyq);   //emptyq,nonempty本身就是结构体的指针     

    }

    int top = QueueFront(nonemptyq);//先保存

    QueuePop(nonemptyq);//再删除

    return top;//再返回

}

5.用队列实现返回栈顶元素

int myStackTop(MyStack* obj) {

    if (!QueueEmpty(&obj->q1))//谁不为空就进谁,直接返回队列的队尾元素

    {

        return QueueBack(&obj->q1);

    }

    else

    {

        return QueueBack(&obj->q2);

    }

}

6.用队列实现栈空的判断

bool myStackEmpty(MyStack* obj) {

    return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);

//两个队列都是空,栈中才没有元素

}

7.用队列实现栈的销毁

void myStackFree(MyStack* obj) {

    QueueDestroy(&obj->q1);

    QueueDestroy(&obj->q2);

    free(obj);

}

注意:这里不能直接free(obj),q1,q2开辟了两个空间的。

8.测试用例

这样你就可以调试找出你的问题啦

int main()
{
    MyStack* obj = myStackCreate();
    myStackPush(obj, 1);
    myStackPush(obj, 2);
    printf("%d ", myStackTop(obj));

    printf("%d ", myStackPop(obj));
    myStackEmpty(obj);
    return 0;

}

三、完整代码

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QueueDestroy(Queue* pq)
{
	assert(pq);

	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}

	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}

	newnode->val = x;
	newnode->next = NULL;

	if (pq->ptail == NULL)
	{
		pq->ptail = pq->phead = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}


void QueuePop(Queue* pq)
{
	assert(pq);
	//空
	assert(pq->phead);

	QNode* del = pq->phead;
	pq->phead = pq->phead->next;
	free(del);
	del = NULL;

	if (pq->phead == NULL)
		pq->ptail = NULL;
	pq->size--;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	// 
	assert(pq->ptail);

	return pq->ptail->val;
}

bool QueueEmpty(Queue* pq)
{
	assert(pq);

	return pq->phead == NULL;
}

int QueueSize(Queue* pq)
{
	assert(pq);

	return pq->size;
}


typedef struct {
	Queue q1;
	Queue q2;
} MyStack;


MyStack* myStackCreate() {
	MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
	QueueInit(&pst->q1);
	QueueInit(&pst->q2);
	return pst;

}

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);
}

结语:

       随着这篇关于题目解析的博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。解题的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。

       在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。         你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容,让我们在知识的道路上共同前行。

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值