题目描述
有了上篇博客用队列实现栈的基础,这道题应该会容易一些
本质就是要 用两个 先进后出的 栈 来实现 队列的 先进先出的功能
思路形成~
我们直接来演示一下用栈模拟实现队列的先进先出的操作~~~
开始时两个栈均为空
入数据1 (两个栈为空,随便入一个即可~)
入数据2,3,4
出数据~
现在需要出数据了~,要实现的是队列的先进先出,1是最先进来的,因此我们现在需要出数据1
显然根据上道题的思路,我们需要捯数据,注意栈是后进先出~
第一个栈只剩下1了,我们直接pop掉就可以
继续出数据~
刚才把1pop掉了,现在如果想继续pop呢?根据队列先进先出原则,下来应该pop2,这时我们发现不需要捯数据了,2此时就在第二个栈的栈顶,直接从栈顶弹出即可~
所以从这步就可以看出,这道题和上道题实现思路是有差异的~
我们不妨这样,队列入数据都进第一个栈,队列出数据时如果第二个栈不为空,就直接从第二个栈出数据,如果第二个栈为空,就把第一个栈中的所有数据都捯到第二个栈后再出数据,总之出数据都从第二个栈出,我们分析一下这样是否可行~
现在接着上面的情况继续分析~~
现在又需要入数据5,6
根据我们的想法,直接让数据入第一个栈~
继续出数据
按照上面想法,出数据时第二个栈不为空,直接出数据~
继续出数据~
按照上面想法,出数据时第二个栈为空,先把所有数据捯到第二个栈后再出数据~
可以看到,入数据是1,2,3,4,5,6,出数据也是1,2,3,4,5,6,符合队列先进先出的特点,所以我们的想法是没有问题的
到这思路就厘清了~
最终思路:
定义两个栈,第一个栈叫pushst,就是专门用来入数据的,第二个栈叫popst, 专门用来出数据~
题目所给函数原型
代码实现
下面需要用到栈的相关操作,我们之前就已经实现过,直接把代码搬过来~
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
//栈初始化
void STInit(ST* pst);
//栈的销毁
void STDestory(ST* pst);
//压栈
void STPush(ST* pst,STDataType x);
//出栈
void STPop(ST* pst);
//获取栈顶元素
STDataType STTop(ST* pst);
//判空
bool STEmpty(ST* pst);
//获取size
int STSize(ST* pst);
//栈的初始化
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->top = -1; //top指向栈顶元素
pst->top = 0; //top指向栈顶元素的下一个位置
pst->capacity = 0;
}
//栈的销毁
void STDestory(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = pst->capacity = 0;
}
//压栈
void STPush(ST* pst, STDataType x)
{
if (pst->top == pst->capacity)
{
int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = realloc(pst->a, newCapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail\n");
return;
}
pst->a = tmp;
pst->capacity = newCapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
//出栈
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->top--;
}
//获取栈顶元素
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
//判空
bool STEmpty(ST* pst)
{
return pst->top == 0;
//或者写成
// return !(pst->top)
}
//获取栈中元素个数
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
这两个功能我们选择先实现第二个peek,然后在pop函数中就可以调用peek函数
①定义包含两个栈的队列的结构
typedef struct {
ST popst;
ST pushst;
} MyQueue;
②创建包含两个栈的队列
记着创建栈的同时对其初始化~
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
if(obj == NULL)
{
perror("malloc");
return NULL;
}
STInit(&obj->pushst);
STInit(&obj->popst);
return obj;
}
③队列入数据
只需要对于pushst进行压栈操作~
void myQueuePush(MyQueue* obj, int x) {
STPush(&obj->pushst, x);
}
④返回队头元素
int myQueuePeek(MyQueue* obj) {
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst, STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
return STTop(&obj->popst);
}
这就是我们前面说的,pushst栈中有数据时,先捯到popst,再获取popst栈顶(队头)元素,pushst没有数据时,直接获取popst栈顶返回即可
⑤队头移除元素并返回
调用peek的好处就是如果popst中有数据,就可以直接把数据都捯过来,保证了popst的栈顶元素一定是队目前所有元素中最先进入的(队头元素)
int myQueuePop(MyQueue* obj) {
int front = myQueuePeek(obj);
STPop(&obj->popst);
return front;
}
⑥判断队列是否为空
队列为空就是两个栈均为空~
bool myQueueEmpty(MyQueue* obj) {
return STEmpty(&obj->pushst)
&& STEmpty(&obj->popst);
}
⑦销毁队列
不仅要释放掉队列,还要释放掉底层占据空间的两个栈哦~
void myQueueFree(MyQueue* obj) {
STDestory(&obj->pushst);
STDestory(&obj->popst);
free(obj);
}
完整代码
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
//栈初始化
void STInit(ST* pst);
//栈的销毁
void STDestory(ST* pst);
//压栈
void STPush(ST* pst,STDataType x);
//出栈
void STPop(ST* pst);
//获取栈顶元素
STDataType STTop(ST* pst);
//判空
bool STEmpty(ST* pst);
//获取size
int STSize(ST* pst);
//栈的初始化
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->top = -1; //top指向栈顶元素
pst->top = 0; //top指向栈顶元素的下一个位置
pst->capacity = 0;
}
//栈的销毁
void STDestory(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->top = pst->capacity = 0;
}
//压栈
void STPush(ST* pst, STDataType x)
{
if (pst->top == pst->capacity)
{
int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
STDataType* tmp = realloc(pst->a, newCapacity * sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail\n");
return;
}
pst->a = tmp;
pst->capacity = newCapacity;
}
pst->a[pst->top] = x;
pst->top++;
}
//出栈
void STPop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
pst->top--;
}
//获取栈顶元素
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
//判空
bool STEmpty(ST* pst)
{
return pst->top == 0;
//或者写成
// return !(pst->top)
}
//获取栈中元素个数
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
typedef struct {
ST popst;
ST pushst;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
if(obj == NULL)
{
perror("malloc");
return NULL;
}
STInit(&obj->pushst);
STInit(&obj->popst);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
STPush(&obj->pushst, x);
}
int myQueuePeek(MyQueue* obj) {
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst, STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
return STTop(&obj->popst);
}
int myQueuePop(MyQueue* obj) {
int front = myQueuePeek(obj);
STPop(&obj->popst);
return front;
}
bool myQueueEmpty(MyQueue* obj) {
return STEmpty(&obj->pushst)
&& STEmpty(&obj->popst);
}
void myQueueFree(MyQueue* obj) {
STDestory(&obj->pushst);
STDestory(&obj->popst);
free(obj);
}
本篇 用栈实现队列题目 就分享到这啦,欢迎大家交流指正~