225. 用队列实现栈
请你仅使用两个队列实现一个后入先出 (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 (双端队列) 来模拟一个队列 , 只要是标准的队列操作即可.
示例:
输入:
["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
提示:
- 1 <= x <= 9
- 最多调用 100 次 push, pop, top 和 empty
- 每次调用 pop 和 top 都保证栈不为空
进阶: 你能否仅用一个队列来实现栈.
用两个队列模拟栈
思路:
从一个队列把数据导入另一个队列时, 数据的顺序没有发生变化.
用两个队列来模拟栈时, 一个队列负责主要工作, 另一个队列负责在模拟弹栈操作时备份数据, 起辅助作用.
模拟弹栈操作时, 将队列1的除了队尾元素外的所有元素出队, 并入队至队列2中. 此时队列1的top指针就指向这个要弹栈的元素了. 弹出这个元素后, 再把队列2的全部元素出队并入队队列1.
只有模拟弹栈操作时才会用到队列2, 其余操作只需要队列1.
代码:
#define MAXSIZE 100 typedef struct { int* queue1; int* queue2; int top1, top2, rear1, rear2; } MyStack; MyStack* myStackCreate() { MyStack* mystack = (MyStack*)malloc(sizeof(MyStack)); mystack->queue1 = (int*)malloc(sizeof(int) * MAXSIZE); mystack->queue2 = (int*)malloc(sizeof(int) * MAXSIZE); mystack->top1 = 0; mystack->top2 = 0; mystack->rear1 = 0; mystack->rear2 = 0; return mystack; } // 入栈, 就是队列1的入队 void myStackPush(MyStack* obj, int x) { obj->queue1[obj->rear1] = x; obj->rear1 = (obj->rear1 + 1) % MAXSIZE; } // 弹栈 int myStackPop(MyStack* obj) { // 第一步, 备份 while ((obj->top1 + 1) % MAXSIZE != obj->rear1) { obj->queue2[obj->rear2] = obj->queue1[obj->top1]; obj->rear2 = (obj->rear2 + 1) % MAXSIZE; obj->top1 = (obj->top1 + 1) % MAXSIZE; } // 第二步, 弹栈 int val = obj->queue1[obj->top1]; obj->top1 = (obj->top1 + 1) % MAXSIZE; // 第三步, 备份复原 while ((obj->top2) != (obj->rear2)) { obj->queue1[obj->rear1] = obj->queue2[obj->top2]; obj->rear1 = (obj->rear1 + 1) % MAXSIZE; obj->top2 = (obj->top2 + 1) % MAXSIZE; } return val; } // 取栈顶元素, 就是队列的尾元素 int myStackTop(MyStack* obj) { return obj->queue1[(obj->rear1 - 1 + MAXSIZE) % MAXSIZE]; } // 判断栈是否为空 bool myStackEmpty(MyStack* obj) { if (obj->rear1 == obj->top1) return true; else return false; } // 销毁栈 void myStackFree(MyStack* obj) { obj->top2 = 0; obj->rear2 = 0; free(obj->queue2); obj->top1 = 0; obj->rear1 = 0; free(obj->queue1); } /** * Your MyStack struct will be instantiated and called as such: * MyStack* obj = myStackCreate(); * myStackPush(obj, x); * int param_2 = myStackPop(obj); * int param_3 = myStackTop(obj); * bool param_4 = myStackEmpty(obj); * myStackFree(obj); */
用一个队列模拟栈
思路:
与用两个队列模拟栈的区别仅在于弹栈操作. 弹栈前, 将队列的头元素依次放到队列尾即可.
代码:
#define MAXSIZE 100 typedef struct { int* queue; int top, rear; } MyStack; MyStack* myStackCreate() { MyStack* mystack = (MyStack*)malloc(sizeof(MyStack)); mystack->queue = (int*)malloc(sizeof(int) * MAXSIZE); mystack->top = 0; mystack->rear = 0; return mystack; } void myStackPush(MyStack* obj, int x) { obj->queue[obj->rear] = x; obj->rear = (obj->rear + 1) % MAXSIZE; } int myStackPop(MyStack* obj) { // 因为下面的代码导致rear在变化,所以要保存这个初始的rear int tmp = obj->rear; while ((obj->top + 1) % MAXSIZE != tmp) { obj->queue[obj->rear] = obj->queue[obj->top]; obj->rear = (obj->rear + 1) % MAXSIZE; obj->top = (obj->top + 1) % MAXSIZE; } int val = obj->queue[obj->top]; obj->top = (obj->top + 1) % MAXSIZE; return val; } int myStackTop(MyStack* obj) { return obj->queue[(obj->rear - 1 + MAXSIZE) % MAXSIZE]; } bool myStackEmpty(MyStack* obj) { if (obj->rear == obj->top) return true; else return false; } void myStackFree(MyStack* obj) { obj->top = 0; obj->rear = 0; free(obj->queue); } /** * Your MyStack struct will be instantiated and called as such: * MyStack* obj = myStackCreate(); * myStackPush(obj, x); * int param_2 = myStackPop(obj); * int param_3 = myStackTop(obj); * bool param_4 = myStackEmpty(obj); * myStackFree(obj); */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术