思路:利用两个栈实现队列先进先出的特性,先将元素导入一个栈内
模拟出队时,则将所有元素导入另一个栈内,此时元素顺序被反转过来,只需要取栈顶数据即可
那我们就可以将两个栈的功能分开,一个专门入push,一个专门出pop。出数据时,如果popst为空,则将pushst的数据导入。
假设pushst入了1234后,反转到popst后,pushst又入了56,这时也是可以的。因为先pop4次,将1 2 3 4依次出栈,popst为空,则再将56导入,再pop2次,以5 6依次出栈。最终依然是1 2 3 4 5 6先入先出的顺序。
实现: 因为C语言没有库可以现成使用,所以我们将写好的栈导入
先创建MyQueue结构体,包含两个栈结构体。再malloc动态申请MyQueue结构体的空间,最后将两个栈传入初始化函数,进行初始化(记得要加上&取地址符号)
入队过程 ,我们把数据全部导入pushst栈内即可
因为peek的功能比较简单,只用返回队列开头元素,所以我们先实现这个功能,等会实现pop再复用peek。
返回队列开头元素,我们的核心思路,先判断popst是否为空,如果为空,则循环将pushst中的元素全部导入popst(注意:每取出一个栈顶元素,就将该元素pop出栈),最后获取popst的栈顶元素即可
出队过程,复用peek的功能,先用front保存队头元素,再将popst的栈顶元素弹出,最后返回front即可
判断栈是否为空,只要当两个栈pushst和popst全为空时,队列才为空,返回true,否则返回false
最后,释放队列空间,可能有人只写了最后一句也给过了,但是其实这是不对的。正确做法是,先将两个栈都销毁(销毁数组),再将MyQueue空间给释放掉,这样才不会造成内存泄漏
完整代码附上:
- typedef int STDataType;
- typedef struct Stack
- {
- STDataType* a;
- int top;
- int capacity;
- }ST;
-
- //初始化
- void STInit(ST* pst);
- //销毁
- void STDestroy(ST* pst);
- //压栈
- void STPush(ST* pst, STDataType x);
- //出栈
- void STPop(ST* pst);
- //获取栈顶元素
- STDataType STTop(ST* pst);
- //检测栈是否为空
- bool STEmpty(ST* pst);
- //检测栈中有效元素个数
- int STSize(ST* pst);
-
- void STInit(ST* pst)
- {
- assert(pst);
-
- pst->a = NULL;
- pst->top = 0;//top指向栈顶元素的下一个位置
- pst->capacity = 0;
- }
-
- void STDestroy(ST* pst)
- {
- assert(pst);
-
- free(pst->a);
- pst->top = pst->capacity = 0;
- }
-
- void STPush(ST* pst, STDataType x)
- {
- assert(pst);
-
- if (pst->top == pst->capacity)
- {
- int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2;
- STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
-
- if (tmp == NULL)
- {
- perror("realloc fail");
- return;
- }
-
- pst->a = tmp;
- pst->capacity = newCapacity;
- }
-
- pst->a[pst->top++] = x;
- }
-
- 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)
- {
- assert(pst);
-
- return pst->top == 0;
- }
-
- int STSize(ST* pst)
- {
- assert(pst);
-
- return pst->top;
- }
-
-
- 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) {
- int front = myQueuePeek(obj);
- 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);
- }
- }
-
- return STTop(&obj->popst);
- }
-
- bool myQueueEmpty(MyQueue* obj) {
- return STEmpty(&obj->pushst)
- && STEmpty(&obj->popst);
- }
-
- void myQueueFree(MyQueue* obj) {
- STDestroy(&obj->pushst);
- STDestroy(&obj->popst);
- free(obj);
- }
-
- /**
- * Your MyQueue struct will be instantiated and called as such:
- * MyQueue* obj = myQueueCreate();
- * myQueuePush(obj, x);
-
- * int param_2 = myQueuePop(obj);
-
- * int param_3 = myQueuePeek(obj);
-
- * bool param_4 = myQueueEmpty(obj);
-
- * myQueueFree(obj);
- */