题目描述
描述
请你仅使用两个栈实现一个先入先出的队列,队列应当支持一般队列支持的所有操作(push、peek、pop、empty)
实现MyQueue类:
1、void push(int x)将元素x推入队列的末尾。方法:往pushST中入数据。
2、int pop()从队列的开头移除并返回元素。方法:将pushST中的数据pop掉,放入popST中,再出栈顶的数据。
3、int peek()返回队列开头的元素。方法:如果popST为空,则先将pushST中的数据导入popST中,再返回栈顶的数据。否则直接返回popST栈顶的数据。
4、boolean empty()如果队列为空,返回true,否则返回false。方法:当两个栈的数据都为空,则栈为空。
注意:
1、队列是先进先出。2、栈是后进先出。
3、C语言没有现成的栈,使用自己实现的栈结构,详情参考【数据结构和算法】 - 栈
解题分析:
思路:
核心思路:符合先进先出
假设pushA和popB栈,入了1234,如何使得先出1?
1、入数据的时候,往pushA栈中,入数据
2、出数据的时候,依次将pushA栈所有的数据从栈顶出数据,转移到popB栈中保存,然后往popB栈顶出数据。
3、只有当popB栈中所有的数据都出完后,再将pushA栈中的数据转移到popB栈中,继续出数据。
假设:先1 2 3 4入A中,再pop掉4 3 2 1放入到B中,最后再pop掉1。
如果要入数据,再向A中入5 6。先出完B中的数据,再pop掉5 6放入到B中,最后再pop掉6。
代码实现:
1、MyQueue* myQueueCreate();创建队列
#include "Stack.h"
typedef struct {
ST pushST;
ST popST;
}MyQueue;
MyQueue* myQueueCreate()
{
MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
if (q == NULL)
return NULL;
//队列由两个栈pushST和popST组成,pushST和popST是由数组组成
StackInit(&q->pushST);
StackInit(&q->popST);
return q;
//为什么不定义MyQueue* q;再返回&q。因为不能返回局部变量的地址。你也可以使用传址调用通过形参返回。
}
2、void myQueuePush(MyQueue* obj, int x);入队列
//入数据,往pushA栈中,入数据
void myQueuePush(MyQueue* obj, int x)
{
assert(obj);
//在pushST栈中入数据
StackPush(&obj->pushST, x);
}
3、int myQueuePop(MyQueue* obj);出队列
//出数据的候,将pushA栈依次从栈顶出数据,转移(栈入数据)到popB栈中保存,然后往popB栈顶出数据。
//移出并返回队头元素
int myQueuePop(MyQueue* obj)
{
assert(obj);
//在popST栈中出数据(出数据时,只有当PopST栈没有数据才从PushST倒过去后,
//再出数据,因为只有倒过来的数据才符合先进先出的顺序,否则直接在popST中出数据)
if (StackEmpty(&obj->popST))
{
while (!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST, StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
//popST不为空,直接取数据
int front = StackTop(&obj->popST);
StackPop(&obj->popST);
return front;//返回队头元素
}
4、int myQueuePeek(MyQueue* obj);获取队头元素
//返回队头元素
int myQueuePeek(MyQueue* obj)
{
assert(obj);
//如果popST中没有数据,将PushST中的数据导过去,再返回popST栈顶数据
if (StackEmpty(&obj->popST))
{
while (!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST, StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
//如果popST不为空,直接取栈顶数据
return StackTop(&obj->popST);
}
5、bool myQueueEmpty(MyQueue* obj);判断队列是否为空
bool myQueueEmpty(MyQueue* obj)
{
assert(obj);
//两个栈都为空,则队列为空
return StackEmpty(&obj->popST) && StackEmpty(&obj->pushST);
}
6、void myQueueFree(MyQueue* obj);销毁队列
void myQueueFree(MyQueue* obj)
{
assert(obj);
//注意:队列的结构
StackDestroy(&obj->pushST);
StackDestroy(&obj->popST);
free(obj);
}
代码测试
int main()
{
MyQueue* q = myQueueCreate();
myQueuePush(q, 1);
myQueuePush(q, 2);
myQueuePush(q, 3);
myQueuePush(q, 4);
while (!myQueueEmpty(q))
{
int front = myQueuePeek(q);
printf("%d ", front);
myQueuePop(q);
}
myQueueFree(q);
return 0;
}
总结:
1、入数据的时候,往pushA栈中,入数据
2、出数据的时候,依次将pushA栈所有的数据从栈顶出数据,转移到popB栈中保存,然后往popB栈顶出数据。
3、只有当popB栈中所有的数据都出完后,再将pushA栈中的数据转移到popB栈中,继续出数据。