前言
作者:小蜗牛向前冲
名言:我可以接收失败,但我不能接收放弃
如果觉的博主的文章还不错的话,还请
点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。
为了提高自己编写代码的能力,特意开设刷题专题,记录自己刷题的思路和理解。欢迎❀大家的指正。
在下面的解题中我们都用C语言实现。

在这里我们就是要将队列模拟实现成栈,我们知道队列是先进先出,栈是先进后出;那我们又如何实现呢?其实我们可以借助二个队列实现。下面我们借助图像来理解一下:

首先我们建立二个队列p1,p2,我们可能理解为入栈我们就将入数据到p1处。
其次,我们可以认为p2队列是用来中间存放数据的。
这样我们就成功将5出栈了,如果要将4出栈,那么我们又得需要将p2中的数据倒入到p1中:

这样我们就完成了4出栈。
下面我们简单总结一下思路:
1我们要建立二个队列经行模拟。
2始终保持一个队列为空,在出栈时,将将n-1个数据都倒入到空队列中,那么留在另个队列的数据就可以直接出栈了。
下面是完成的解题代码:
- typedef int QDataType;
- //定义队列
- typedef struct QueueNode
- {
- QDataType data;//数据类型
- struct QueueNode* next;
- }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);
- //返回指向队头的数据的指针
- QDataType QueueFront(Queue* pq);
- //返回指向队尾的数据的指针
- QDataType QueueBack(Queue* pq);
- //判断队列是否为空
- bool QueueEmpty(Queue* pq);
- //返回队列的大小
- int QueueSize(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* del = cur;
- cur = cur->next;//指向下个节点
- free(del);
- }
- pq->head = pq->tail = NULL;//防止出现野指针
- pq->size = 0;
- }
-
- //入队
- void QueuePush(Queue* pq, QDataType x)
- {
- assert(pq);
- //申请节点
- QNode* newNode = (QNode*)malloc(sizeof(QNode));
- if (newNode==NULL)
- {
- perror("malloc fail");
- exit(-1);
- }
- else
- {
- newNode->data = x;
- newNode->next = NULL;
- }
- //队列为空
- if (pq->tail == NULL)
- {
- pq->head = pq->tail = newNode;
- }
- //不为空
- else
- {
- pq->tail->next = newNode;
- pq->tail = newNode;//tail指针指向newNode
- }
- pq->size++;
- }
-
- //出队
- void QueuePop(Queue* pq)
- {
- assert(pq);
- //断言队列是否为空
- assert(!QueueEmpty(pq));
- //当队列中就一个数据时
- if (pq->head->next == NULL)
- {
- free(pq->head);
- pq->head = pq->tail = NULL;
- }
- else
- {
- QNode* del = pq->head;
- pq->head = pq->head->next;//头变为下个节点
- free(del);
- del = NULL;
- }
- pq->size--;
- }
-
- //判断队列是否为空
- bool QueueEmpty(Queue* pq)
- {
- assert(pq);
- return pq->tail == NULL;
- }
-
- //返回指向队头的数据的指针
- 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;
- }
-
- //返回队列的大小
- int QueueSize(Queue* pq)
- {
- return pq->size;
- }
-
- typedef struct {
- Queue p1;//入栈
- Queue p2;//出栈
-
- } MyStack;
-
-
- MyStack* myStackCreate() {
- MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
- //对栈初始化
- QueueInit(&obj->p1);
- QueueInit(&obj->p2);
- return obj;
- }
-
- void myStackPush(MyStack* obj, int x) {
- //当p1为空时就将数据倒入
- if(!QueueEmpty(&obj->p1))
- {
- QueuePush(&obj->p1,x);
- }
- else
- {
- QueuePush(&obj->p2,x);
- }
-
- }
-
- int myStackPop(MyStack* obj) {
- Queue* empty = &obj->p1;//假设p1为空
- Queue* noEmpty = &obj->p2;
- //如果p1队列为非空
- if(!QueueEmpty(&obj->p1))
- {
- empty = &obj->p2;
- noEmpty = &obj->p1;
- }
- //将非空队列中的N-1的数据都倒入到空队列中,那么原队列还剩的1个数据就是要返回的栈顶数据
- while(QueueSize(noEmpty)>1)
- {
- QueuePush(empty,QueueFront(noEmpty));//入栈
- QueuePop(noEmpty);//出栈
- }
- int top = QueueFront(noEmpty);
- QueuePop(noEmpty);//出栈
- return top;
- }
-
- int myStackTop(MyStack* obj) {
- if(!QueueEmpty(&obj->p1))
- {
- return QueueBack(&obj->p1);
- }
- else
- {
- return QueueBack(&obj->p2);
- }
- }
-
- bool myStackEmpty(MyStack* obj) {
- return QueueEmpty(&obj->p1) && QueueEmpty(&obj->p2);
- }
-
- void myStackFree(MyStack* obj) {
- QueueDestroy(&obj->p1);
- QueueDestroy(&obj->p2);
- free(obj);
- }


要用二个栈实现队列,这是很好实现的。
为什么这么说呢?我们可以用栈PushST来模拟入队列,栈PopST模拟出队列。
下面我们顺着这个思路来,来图解一下 1,2,3,4的入队列和出队列的过程。
1数据入队列

2 要出队列时,当PopST为空的时候,就将PushST的数据倒入到PopST中,然后直接出就行。

完整代码:
- typedef int STDataType;
- //定义栈
- typedef struct Stack
- {
- STDataType* arr;//数据类型
- int pos;//数组下标
- 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 StackInit(ST* ps)
- {
- assert(ps);
- ps->arr = NULL;//初始数组为空
- ps->pos = ps->capacity = 0;//初始为0
- }
-
- //销毁
- void StackDestroy(ST* ps)
- {
- assert(ps);
- free(ps->arr);//arr是整个栈的地址
- ps->arr = NULL;
- ps->capacity = ps->pos = 0;
- }
-
- //入栈
- void StackPush(ST* ps, STDataType x)
- {
- assert(ps);
- //判断栈的空间是否满
- if (ps->pos == ps->capacity)
- {
- //扩容
- int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//扩2倍
- STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
- if (tmp == NULL)
- {
- perror("reamlloc fail");
- exit(-1);
- }
- //跟新容量
- ps->arr = tmp;
- ps->capacity = newCapacity;
- }
- //入栈
- ps->arr[ps->pos] = x;
- ps->pos++;//下标++
- }
-
- //出栈
- void StackPop(ST* ps)
- {
- assert(ps);
- //断言栈是否为空
- assert(!StackEmpty(ps));
- --ps->pos;
- }
-
- //判断栈是否为空
- bool StackEmpty(ST* ps)
- {
- assert(ps);
- return ps->pos == 0;
- }
-
- //显示返回栈顶数据
- STDataType StackTop(ST* ps)
- {
- assert(ps);
- //断言栈是否为空
- assert(!StackEmpty(ps));
- return ps->arr[ps->pos - 1];//下标已经前移
- }
-
- //返回栈的长度
- int StackSize(ST* ps)
- {
- assert(ps);
- return ps->pos;
- }
- int StackSize(ST* ps);
-
- typedef struct {
- ST PushST;//入队列
- ST PopST;//出队列
- } MyQueue;
-
-
- MyQueue* myQueueCreate() {
- //为模拟的队列开辟空间
- MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
- //初始化
- StackInit(&obj->PushST);
- StackInit(&obj->PopST);
- return obj;
- }
-
- void myQueuePush(MyQueue* obj, int x) {
- StackPush(&obj->PushST, x);
- }
- void PushSTTOPopST(MyQueue* obj)
- {
- //判断PopST是否为空
- if (StackEmpty(&obj->PopST))
- {
- while (!(StackEmpty(&obj->PushST)))
- {
- StackPush(&obj->PopST, StackTop(&obj->PushST));
- StackPop(&obj->PushST);
- }
- }
- }
-
- int myQueuePop(MyQueue* obj) {
- //将PuahST中的元素都倒入PopST中
- PushSTTOPopST(obj);
- int fornt = StackTop(&obj->PopST);
- StackPop(&obj->PopST);
- return fornt;
- }
-
- int myQueuePeek(MyQueue* obj) {
- //将PuahST中的元素都倒入PopST中
- PushSTTOPopST(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->PushST);
- free(obj);
- }


对于设计循环队列来说有二种思路:
1 用数组实现
2 用链表实现

对于这二种思路,我会首选思路1,为什么会这么说呢?
因为用链表实现循环队列,首先你要malloc多份空间,而且这样你还不好判断循环队列是否已满!
所以:我会选择用思路1来为大家解题。
此题有个重点:那就是如何判断队列是否以满。
因为在对于空和满来说,队列中指针fornt和back都是指向同一个位置。
那么我们这么去解决呢?
我们有二个思路:
1多开辟一块空间
2用size标记队列的长度,当size==k时就满
下面我们用思路1来解决:

代码转换:
- bool myCircularQueueIsFull(MyCircularQueue* obj) {
- return (obj->back + 1) % obj->n == obj->fornt;
-
- }
完整代码:
- typedef struct {
- int* arr;
- int fornt;
- int back;
- int n;
-
- } MyCircularQueue;
-
-
- MyCircularQueue* myCircularQueueCreate(int k) {
- MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
- obj->arr = (int*)malloc(sizeof(int) * (k + 1));
- obj->fornt = obj->back=0;
- obj->n = k + 1;
- return obj;
- }
-
- bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
- return obj->fornt == obj->back;
- }
-
- bool myCircularQueueIsFull(MyCircularQueue* obj) {
- return (obj->back + 1) % obj->n == obj->fornt;
-
- }
-
- bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
- if (myCircularQueueIsFull(obj))
- {
- return false;
- }
- obj->arr[obj->back] = value;
- obj->back++;
- //如果back指针已经指向尾,需要重新指向头
- obj->back %= obj->n;
- return true;
-
- }
-
- bool myCircularQueueDeQueue(MyCircularQueue* obj) {
- if (myCircularQueueIsEmpty(obj))
- {
- return false;
- }
- obj->fornt++;
- //如果fornt指针已经指向尾,需要重新指向头
- obj->fornt %= obj->n;
- return true;
- }
-
- int myCircularQueueFront(MyCircularQueue* obj) {
- if (myCircularQueueIsEmpty(obj))
- {
- return -1;
- }
- return obj->arr[obj->fornt];
- }
-
- int myCircularQueueRear(MyCircularQueue* obj) {
- if (myCircularQueueIsEmpty(obj))
- {
- return -1;
- }
- else if(obj->back==0)
- return obj->arr[obj->n-1];
- else
- return obj->arr[obj->back-1];
- // return obj->arr[(obj->back -1 + obj->n) % obj->n];
- }
-
-
-
- void myCircularQueueFree(MyCircularQueue* obj) {
- free(obj->arr);
- free(obj);
-
- }