目录
前言
我们已经熟悉了栈和队列的基本结构以及它们各自的特点,(还不够熟悉的朋友可以看一下我的另外两篇文章)
队列相关博客:https://blog.csdn.net/m0_73737172/article/details/129908874?spm=1001.2014.3001.5502
栈相关博客:
https://blog.csdn.net/m0_73737172/article/details/129907308?spm=1001.2014.3001.5502
那么接下来我们通过Leetcode中的两道题来实现二者的转化,加深对它们结构的认识。
1.用队列实现栈
思路:要想使用两个队列实现栈,我们首先需要明确二者的性质:队列是先进先出,栈则是后进先出,那么假设我存储的内容是1234,如果是队列,那么假设我要取出一个元素,我取出的是1;如果是栈,那么我取出的是4。这时如果我们想通过队列取出4的话,就需要再用一个队列,先将123存入第二个队列,然后第一个队列只剩下4,再用pop函数即可取出。
ok就按照这个思路,如果我们要取出两个元素,比如34,我们就需要再把3之前的元素存入第一个队列中,同样用pop函数将3从第二个队列中取出。
我们继续这个思路往下走,如果此时我要push数据5和6需要存入哪个队列呢,ok是那个非空队列,那么到这我们就明白了这道题也就是要求我们一个队列存储数据,另一个队列为空,负责在需要出数据时起一个“中转站”的作用。
ok那我们开始代码实现。
由于我们是使用c语言进行实现,所以我们需要先把队列写好:
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Queue;
void QueueInit(Queue* pq);//初始化
void QueueDestroy(Queue* pq);//销毁
void QueuePush(Queue* pq,QDataType x);//插入
void QueuePop(Queue* pq);//删除
int QueueSize(Queue* pq);//队列大小
bool QueueEmpty(Queue* pq);//判空
QDataType QueueFront(Queue* pq);//取队头数据
QDataType QueueBack(Queue* pq);//取队尾数据
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->tail = pq->head = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
if (pq->head == NULL)
{
assert(pq->tail == NULL);
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(pq->head != NULL);
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
pq->size--;
}
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
然后根据Leetcode题目所给的函数进行实现:
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack*pst=(MyStack*)malloc(sizeof(MyStack));
if(pst==NULL)
{
perror("malloc fail");
return NULL;
}
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);
}
2.用栈实现队列
类比用队列实现栈,我们用两个栈来实现队列,首先我们按照队列实现栈的思路看看是否可行,我们仍然让一个栈为空,另一个栈存入1234,那么如果是队列的话,要取出一个元素则为1,那么我们按照栈的性质,需要先将234存到另一个栈中,此时即可把1取出,那么此时如果我们要继续取出元素呢,按照队列依次取出的是234,那么我们现在看存有数据的那个栈会发现,234相比之前倒置了,也就是我们直接将第二个栈中的数据依次取出即可,不需要像之前用队列实现栈那样需要不断地转置。
那么我们继续思考,如果此时我们要继续往进存数据比如56呢,思考一下我们需要再将原先的234倒回另一个栈中吗?如果不倒的话会不会乱呢?
答案是不需要倒回去,我们可以直接将需要插入的数据56存入空栈中,也就是我们现在将原先的空栈只用来存放数据,需要push数据就存入栈A(为了方便我们将该栈记作栈A,另一个记作栈B),需要pop数据就对栈B进行操作,当栈B中的数据都pop之后,如果还要pop就将栈A中的数据存入栈B中,继续如上操作即可。
有了上面的思路我们就可以开始代码实现了:
我们还是需要先将栈的基本结构写好:
typedef int STDataType;
typedef struct Stack
{
int* a;
int top;
int capacity;
}ST;
void STInit(ST* ps);//初始化
void STPush(ST* ps, STDataType x);//插入
void STPop(ST* ps);//删除
int STSize(ST* ps);//栈的大小
bool STEmpty(ST* ps);//判空
void STDestroy(ST* ps);//销毁
STDataType STTop(ST* ps);//访问栈顶元素
void STInit(ST* ps)
{
assert(ps);
ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
if (ps->a == NULL)
{
perror("malloc fail");
return;
}
ps->capacity = 4;
ps->top = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->top == ps->capacity)
{
STDataType* tmp = (STDataType*)realloc(ps->a,sizeof(STDataType) * ps->capacity * 2);
if (ps->a == NULL)
{
perror("calloc fail");
return;
}
ps->a = tmp;
ps->capacity *= 2;
}
ps->a[ps->top] = x;
ps->top++;
}
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
void STPop(ST* ps)
{
assert(ps);
assert(!STEmpty(ps));
ps->top--;
}
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
STDataType STTop(ST* ps)
{
assert(ps);
assert(!STEmpty(ps));
return ps->a[ps->top - 1];
}
接下来就是题目所给的函数实现:
typedef struct {
ST pushst;
ST popst;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
if(obj==NULL)
{
perror("malloc fail");
return NULL;
}
STInit(&obj->pushst);
STInit(&obj->popst);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
STPush(&obj->pushst,x);
}
int myQueuePop(MyQueue* obj) {
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst,STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
int front=STTop(&obj->popst);
STPop(&obj->popst);
return front;
}
int myQueuePeek(MyQueue* obj) {
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst,STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
int fornt=STTop(&obj->popst);
return fornt;
}
bool myQueueEmpty(MyQueue* obj) {
return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}
void myQueueFree(MyQueue* obj) {
STDestroy(&obj->pushst);
STDestroy(&obj->popst);
free(obj);
}
到这呢我们这两个题目的解答就结束了,你对栈和队列掌握了么?