🌈欢迎来到数据结构专栏~~栈和队列oj题
- (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是Scort🎓
- 🌍博客主页:张小姐的猫~江湖背景🌍
- 快上车🚘,握好方向盘跟我有一起打天下嘞!
- 送给自己的一句鸡汤🤔:
- 🔥集中起来的意志可以击穿顽石🔥
- 🙏作者水平很有限,如果发现错误,可在评论区指正,感谢🙏
- 🎉🎉欢迎持续关注!🎉🎉
2道栈和队列面试真题超详剖析
- 🌈欢迎来到数据结构专栏~~栈和队列oj题
-
- 🌍第1️⃣题:用栈实现队列
- 🌍第2️⃣题:用队列实现栈
- 原码直出
- 📢写在最后
🌍第1️⃣题:用栈实现队列
🏷️力扣地址:🌈232. 用栈实现队列
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push
、pop
、peek
、empty
):
实现 MyQueue
类:
void push(int x)
将元素 x 推到队列的末尾int pop()
从队列的开头移除并返回元素int peek()
返回队列开头的元素boolean empty()
如果队列为空,返回 true ;否则,返回 false
示例1:
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false
💫关键思路:
- 为了满足队列的 FIFO(
先进先出
) 的特性,我们需要用到两个栈
,用它们其中一个来反转
元素的入队顺序,用另一个来存储
元素的最终顺序。 - popst出栈 ——pushst入栈
1️⃣pop接口
- 出数据时,把pushst中的数据
倒腾
到popst中,实现了先进先出
。 - 此后,若要
出数据
,直接在popst出栈
即可。若出空了,就再如上倒腾一下,那此时就可以按照栈的特性去pop,达到队列的LIFO的目的
🌠动图解析:👇🏻
2️⃣peek接口
- 判断
出数据的栈popst
是否为空,若为空,则要把pushst栈的数据倒腾
过来,否则可以直接出栈顶数据
🌠动图解析:👇🏻
3️⃣push接口
- 就只管往
pushst
中入就行,保持了数据的顺序。
🌠动图解析:👇🏻
4️⃣empty接口
- 判断两个栈是否
都为NULL
,是则返回true
,否则返回false
💡代码实现:
typedef struct {
ST pushst;
ST popst;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue*obj = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&obj->pushst);
StackInit(&obj->popst);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->pushst,x);
}
int myQueuePop(MyQueue* obj) {
if(StackEmpty(&obj->popst))
{
//如果pop栈为空,则把push栈的数据倒过去
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) {
if(StackEmpty(&obj->popst))
{
//如果pop栈为空,则把push栈的数据倒过去
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->popst);
StackDestroy(&obj->pushst);
free(obj);
}
🌍第2️⃣题:用队列实现栈
🏷️力扣地址:🌈225. 用队列实现栈
请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push
、top
、pop
和 empty
)。
实现 MyStack
类:
void push(int x)
将元素 x 压入栈顶int pop()
移除并返回栈顶元素。int top()
返回栈顶元素。boolean empty()
如果栈是空的
,返回true
;否则,返回 false
。
示例1
输入:
["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️⃣pop接口
- 把非空队列的前(n-1)个数据依次转移(
倒腾
)到另一个队列里,最后一个数据pop
掉。即可实现后进先出。
🌠动图解析:👇🏻
2️⃣push接口
- 哪一个队列
非空
,就入哪一个队
。保持数据顺序
🌠动图解析:👇🏻
3️⃣top接口
- 判断两个队列中哪个是
非空队列
,并返回其队尾的结点即可
4️⃣empty接口
- 判断
两个队列
是否都为空
,是则返回true,否则false
💡代码实现:
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() //初始化栈
{
MyStack* obj =(MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) //压栈
{
if(!QueueEmpty(&obj->q1)) //如果q1不为空,则向q1压栈
{
QueuePush(&obj->q1,x);
}
else//q1为空,q2有可能为空,也可能不空
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj)
{
//假设q1为空,q2非空
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);//取出栈顶,记得pop掉
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);//先释放q1、q2,最后再是自定义的栈
QueueDestroy(&obj->q2);
free(obj);
}
原码直出
由于上面都是要借助现成的栈
或者队列
才能实现的,(后面学了c++就不会这么麻烦了),前面都只写了主体逻辑,现在把完整的贴过来嗷,有需要自取
栈实现队列
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
静态
//#define N 10
//typedef int STDataType;
//typedef struct Stack
//{
// STDataType a[N];
// int top;
//}ST;
//动态
typedef int STDataType;
typedef struct Stack
{
STDataType *a;
int top;//栈顶
int capacity;//容量
}ST;
// 初始化栈
void StackInit(ST* ps);
// 入栈
void StackPush(ST* ps, STDataType data);
// 出栈
void StackPop(ST* ps);
// 获取栈顶元素
STDataType StackTop(ST* ps);
// 获取栈中有效元素个数
int StackSize(ST* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(ST* ps);
// 销毁栈
void StackDestroy(ST* ps);
// 初始化栈
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
// 入栈
void StackPush(ST* ps, STDataType data)
{
assert(ps);
if (ps->top == ps->capacity)
{
//满了就扩容
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = data;
ps->top++;
}
// 出栈
void StackPop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));//防止堆顶为空
ps->top--;
}
// 获取栈顶元素
STDataType StackTop(ST* ps)
{
assert(ps);
assert(!StackEmpty(ps));//防止堆顶为空
return ps->a[ps->top - 1];
}
// 获取栈中有效元素个数
int StackSize(ST* ps)
{
assert(ps);
return ps->top;//top就是size个数,看下标
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(ST* ps)
{
return ps->top == 0;
}
// 销毁栈
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
typedef struct {
ST pushst;
ST popst;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue*obj = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&obj->pushst);
StackInit(&obj->popst);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->pushst,x);
}
int myQueuePop(MyQueue* obj) {
if(StackEmpty(&obj->popst))
{
//如果pop栈为空,则把push栈的数据倒过去
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) {
if(StackEmpty(&obj->popst))
{
//如果pop栈为空,则把push栈的数据倒过去
while(!StackEmpty(&obj->pushst))
{
StackPush(&obj->popst,StackTop(&obj->pushst));
StackPop(&obj->pushst);
}
}
return StackTop(&obj->popst);1111111111111111111111111111111111111
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->popst) && StackEmpty(&obj->pushst);
}
void myQueueFree(MyQueue* obj) {
StackDestroy(&obj->popst);
StackDestroy(&obj->pushst);
free(obj);
}
队列实现栈
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
// 链式结构:表示队列
typedef int QDataType;
typedef struct SListNode
{
QDataType data;
struct SListNode* next;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
// 初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->head = q->tail = NULL;//不带哨兵位,哨兵位意义不大
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
printf("malloc failed\n");
exit(-1);
}
newnode->data = data;
newnode->next = NULL;
if (q->tail == NULL)
{
q->head = q->tail = newnode;
}
else
{
q->tail->next = newnode;
q->tail = newnode;
}
}
// 队头出队列
void QueuePop(Queue* q)
{
assert(q);
assert(!QueueEmpty(&q));
//1.一个节点
//2.多个节点
if (q->head->next == NULL)
{
free(q->head);
q->head = q->tail = NULL;//避免野指针
}
else
{
QNode* next = q->head->next;
free(q->head);
q->head = next;
}
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q);
assert(!QueueEmpty(&q));
return q->head->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
assert(q);
assert(!QueueEmpty(&q));
return q->tail->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q);
QNode* cur = q->head;
int Size = 0;
while (cur)
{
Size++;
cur = cur->next;
}
return Size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{
assert(q);
return q->head == NULL;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
q->head = q->tail = NULL;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() //初始化栈
{
MyStack* obj =(MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) //压栈
{
if(!QueueEmpty(&obj->q1)) //如果q1不为空,则向q1压栈
{
QueuePush(&obj->q1,x);
}
else//q1为空,q2有可能为空,也可能不空
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj)
{
//假设q1为空,q2非空
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);//取出栈顶,记得pop掉
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);//先释放q1、q2,最后再是自定义的栈
QueueDestroy(&obj->q2);
free(obj);
}
📢写在最后
- 能看到这里的都是棒棒哒🙌!
- 想必《栈和队列》也算是数据结构中比较难🔥的部分了,如果认真看完以上部分,肯定有所收获。
- 接下来我还会继续写关于📚《
循环队列
》等… - 💯如有错误可以尽管指出💯
- 🥇想学吗?我教你啊🥇
- 🎉🎉觉得博主写的还不错的可以
一键三连撒
🎉🎉
相关文章
暂无评论...