1.使用两个栈结构构建队列
我们需要自定义栈及其相关操作
栈结构遵循后入先出的原则,队列结构遵循先入先出的原则
构建具有两个栈结构的队列,栈pushST用于数据的插入,栈popST用于数据的删除
为栈结构动态开辟空间并初始化栈结构
//定义一个具有两个栈的队列结构
typedef struct {
ST pushST;//插入数据栈
ST popST;//删除数据栈
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
//内存开辟失败
if(obj == NULL)
{
perror("malloc fail");
exit(-1);
}
//开辟成功,初始化
else
{
StackInit(&obj->pushST);
StackInit(&obj->popST);
}
return obj;
}
2.入队操作
模拟入队操作,即将所有元素压栈即可,这里我们将数据压入栈pushST
void myQueuePush(MyQueue* obj, int x) {
//把数据压入插入数据专用栈
StackPush(&obj->pushST,x);
}
3.出队操作
模拟队列的出队操作:队列出队访问的是队头数据,即先进入结构的数据,在栈中即为栈底元素,要访问栈底元素,需要后入的元素先出栈才能访问
以上操作后,栈pushST和栈popST的结构如下:
此时栈pushST的栈顶元素即模拟队列的队头元素,存储并出栈即可
以上操作进行完之后需要将栈popST中的数据还原回pushST吗?
分析:不需要将栈popST中的数据还原回pushST,当进行下一次模拟出队操作时,只需要访问栈popST的栈顶元素即可,栈popST栈顶的元素为先进入栈pushST的元素;若popST为空,则重新进行上述步骤即可
📖Note:
栈结构遵循先进先出的原则,当我们把pushST栈中的元素依次出栈再入栈popST时,元素入栈popST顺序刚好与之前的入栈pushST的先后顺序相反,从而使这些元素出栈popST时栈顶刚好是先入栈pushST的元素
//将pushST中元素外依次倒入popST
void pushSTPopST(MyQueue* obj)
{
if(StackEmpty(&obj->popST))
{
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
}
int myQueuePop(MyQueue* obj) {
pushSTPopST(obj);
int front = StackTop(&obj->popST);
StackPop(&obj->popST);
return front;
}
4.访问队列的开头元素
队列的开头元素即pushST栈中的栈底元素,将栈pushST中的所有元素入到栈popST中,再访问栈popST的栈顶元素即可
int myQueuePeek(MyQueue* obj) {
pushSTPopST(obj);
return StackTop(&obj->popST);
}
5.判断队列是否为空
队列结构为两个栈结构构成的,当两个栈都为空的时候,队列即为空
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->pushST) && StackEmpty(&obj->popST);
}
6.空间释放
构建的队列结构动态开辟了空间,所有操作结束后,需要释放空间,否则会造成内存泄漏
void myQueueFree(MyQueue* obj) {
StackDestroy(&obj->pushST);
StackDestroy(&obj->popST);
}
参考代码如下:
//栈的相关定义
typedef int STDataType;
//动态内存开辟
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
//初始化
void StackInit(ST* ps);
//销毁
void StackDestroy(ST* ps);
//插入数据
void StackPush(ST* ps, STDataType x);
//删除数据
void StackPop(ST* ps);
//访问栈顶数据
STDataType StackTop(ST* ps);
//判断是否为空栈
bool StackEmpty(ST* ps);
//访问栈中数据
void StackPopAll(ST* ps);
//计算栈的大小
int StackSize(ST* ps);
//初始化
void StackInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
//销毁
void StackDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
//插入数据
void StackPush(ST* ps, STDataType x)
{
assert(ps);
//扩容
if (ps->top == ps->capacity)
{
int newcapacity = ps->capacity == 0 ? 4 : (ps->capacity) * 2;
STDataType* tmp = realloc(ps->a, newcapacity * sizeof(STDataType));
//扩容失败
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
//扩容成功
ps->a = tmp;
ps->capacity = newcapacity;
}
//插入数据
ps->a[ps->top] = x;
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];
}
//判断是否为空栈
bool StackEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
//计算栈的大小
int StackSize(ST* ps)
{
assert(ps);
return ps->top;
}
//定义一个具有两个栈的队列结构
typedef struct {
ST pushST;//插入数据栈
ST popST;//删除数据栈
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
//内存开辟失败
if(obj == NULL)
{
perror("malloc fail");
exit(-1);
}
//开辟成功,初始化
else
{
StackInit(&obj->pushST);
StackInit(&obj->popST);
}
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
//把数据压入插入数据专用栈
StackPush(&obj->pushST,x);
}
//将pushST中元素外依次倒入popST
void pushSTPopST(MyQueue* obj)
{
if(StackEmpty(&obj->popST))
{
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST,StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
}
int myQueuePop(MyQueue* obj) {
pushSTPopST(obj);
int front = StackTop(&obj->popST);
StackPop(&obj->popST);
return front;
}
int myQueuePeek(MyQueue* obj) {
pushSTPopST(obj);
return StackTop(&obj->popST);
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->pushST) && StackEmpty(&obj->popST);
}
void myQueueFree(MyQueue* obj) {
StackDestroy(&obj->pushST);
StackDestroy(&obj->popST);
}