目录
*核心思想:一个队列用于存数据,另一个队列用于在非空队列需要出队尾数据时,存其他的数据。
题目的所有代码在文章末尾处
a.题目链接
有效的括号https://leetcode.cn/problems/implement-stack-using-queues/description/
b.题目
请你仅使用两个队列实现一个后入先出(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(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
1 <= x <= 9
- 最多调用
100
次push
、pop
、top
和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);
}
结语:
随着这篇关于题目解析的博客接近尾声,我衷心希望我所分享的内容能为你带来一些启发和帮助。解题的过程往往充满挑战,但正是这些挑战让我们不断成长和进步。我在准备这篇文章时,也深刻体会到了学习与分享的乐趣。
在此,我要特别感谢每一位阅读到这里的你。是你的关注和支持,给予了我持续写作和分享的动力。我深知,无论我在某个领域有多少见解,都离不开大家的鼓励与指正。因此,如果你在阅读过程中有任何疑问、建议或是发现了文章中的不足之处,都欢迎你慷慨赐教。 你的每一条反馈都是我前进路上的宝贵财富。同时,我也非常期待能够得到你的点赞、收藏,这将是对我莫大的支持和鼓励。当然,我更期待的是能够持续为你带来有价值的内容,让我们在知识的道路上共同前行。