队列算法精讲:从栈与队列互实现到循环队列(待补充)
目录
- 前言
- 一、队列算法题
- 1.1 用队列实现栈
- 1.2 用栈实现队列
- 1.3 设计循环队列
- 结语
前言
大家好啊,我是云泽Q,一名热爱计算机技术的在校大学生。近几年人工智能技术飞速发展,为了帮助大家更好地抓住这波浪潮,在开始正文之前,我想先为大家推荐一个非常优质的人工智能学习网站)。它提供了从基础到前沿的系列课程和实战项目,非常适合想要系统入门和提升AI技术的朋友,相信能对你的学习之路有所帮助。
一、队列算法题
1.1 用队列实现栈
用队列实现栈
队列先进先出
- 入栈:往不为空的队列中插入数据
- 出栈:把不为空队列中前size-1个数据挪到另一个队列,再将最后一个数据出队列
此时q2不为空
此时q1不为空
最后直接将最后一个数据出队列
- 取栈顶:取栈顶不能按之前出栈的老套路,如果将前size-1个数据挪到另一个队列,取栈顶不同于出栈,是不出数据的,此时q1有1个数据,q2有3个数据,此时就会导致两个队列均不为空,完成第一次取栈顶后,就无法完成出栈了
所以正确的取栈顶方式就是前size-1不挪数据,找不为空的队列,返回队尾数据
创建一个栈的返回值是一个指向上面结构体的指针,所以要向操作系统申请一个MyStack大小的空间,空间申请下来了,指针才能指向MyStack,pst指向操作系统申请的一个栈大小的空间
完整源码
typedef int QDataType;
//定义节点结构
typedef struct QueueNode
{QDataType data;struct QueueNode* next;
}QueueNode;
//定义队列结构
typedef struct Queue
{QueueNode* phead;//队头QueueNode* ptail;//队尾//int size; //队列中有效元素个数
}Queue;//初始化
void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;//pq->size = 0;
}//入队--队尾
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("malloc fail!");exit(1);}newnode->data = x;newnode->next = NULL;if (pq->phead == NULL){pq->phead = pq->ptail = newnode;//pq->size++;}else {pq->ptail->next = newnode;pq->ptail = pq->ptail->next;//pq->size++;}
}//判断队列是否为空
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}//出队--对头
void QueuePop(Queue* pq)
{assert(!QueueEmpty(pq));if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;//pq->size--;}else {QueueNode* next = pq->phead->next;free(pq->phead);pq->phead = next;//pq->size--;}
}//取对头数据
QDataType QueueFront(Queue* pq)
{assert(!QueueEmpty(pq));return pq->phead->data;
}//取队尾数据
QDataType QueueBack(Queue* pq)
{assert(!QueueEmpty(pq));return pq->ptail->data;
}//队列中有效元素个数
int QueueSize(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;int size = 0;while (pcur){++size;pcur = pcur->next;}return size;//return pq->size;
}//销毁队列
void QueueDestory(Queue* pq)
{assert(pq);QueueNode* pcur = pq->phead;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->phead = pq->ptail = NULL;
}//----------------------以上是队列的结构和常用的方法-------------------------typedef struct {Queue q1;Queue q2;
} MyStack;//创建一个栈
MyStack* myStackCreate() {MyStack* pst=(MyStack*)malloc(sizeof(MyStack));//初始化队列QueueInit(&pst->q1);QueueInit(&pst->q2);return pst;
}//入栈
void myStackPush(MyStack* obj, int x) {//往不为空的队列中插入数据if(!QueueEmpty(&obj->q1)){QueuePush(&obj->q1,x);}else{QueuePush(&obj->q2,x);}
}//出栈
int myStackPop(MyStack* obj) {//找不为空队列//假设q1为空,q2非空Queue* emp=&obj->q1;Queue* noneEmp=&obj->q2;if(QueueEmpty(&obj->q2)){emp=&obj->q2;noneEmp=&obj->q1;}//将不为空队列前size-1个数据挪到空队列中while(QueueSize(noneEmp)>1){//取队头,入另一个队列,这里也可以用一个变量来接收队头,然后再入队列QueuePush(emp,QueueFront(noneEmp));//出队头QueuePop(noneEmp);}//不为空队列最后一个数据出队int top=QueueFront(noneEmp);QueuePop(noneEmp);return top;
}//取栈顶
int myStackTop(MyStack* obj) {//找不为空队列,返回不为空队列的队尾数据if(!QueueEmpty(&obj->q1)){return QueueBack(&obj->q1);}else{return QueueBack(&obj->q2);}
}//判断栈是否为空
bool myStackEmpty(MyStack* obj) {return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}//栈的销毁
void myStackFree(MyStack* obj) {QueueDestory(&obj->q1);QueueDestory(&obj->q2);free(obj);obj=NULL;
}/*** Your MyStack struct will be instantiated and called as such:* MyStack* obj = myStackCreate();* myStackPush(obj, x);* int param_2 = myStackPop(obj);* int param_3 = myStackTop(obj);* bool param_4 = myStackEmpty(obj);* myStackFree(obj);
*/
1.2 用栈实现队列
用栈实现队列
这里思路就要转变了,一个栈用来入数据,一个栈用来出数据
- 入队列:往pushST插入数据
若popST中没有数据,则将pushST中的数据全部导入popST中,然后出popST中的数据
还有一种情况,先在pushST中插入1,2
此时popST中为空,没有数据可出,将pushST中的数据导过去
之后将1出数据,此时又在pushST中入队列3,4
此时popST不为空,就直接出数据,此时popST中为空了,再进行导数据
导完了之后再出数据
- 也就是出队列这里有一个前提,popST不为空直接出,否则将pushST中的数据先导过去再出数据
接下来就是取队头
popST为空,先导数据
此时1是队头,便取队头,注意是取不是出,然后出数据
之后就正常取队头,出对头就可以了,因为popST不为空,栈顶就是队头数据,不用导数据
- 逻辑和队列一样,但是不出数据,popST不为空直接取队头,否则将pushST中的数据先导过去再取队头
返回值MyQueue* 是指向MyQueue这个结构的指针,所以像操作系统申请一个MyQueue大小的空间
完整源码
//定义栈的结构 - Stack是栈的名称
typedef int STDataType;
typedef struct Stack {STDataType* arr;//存储数据的数组int top;//top指向栈顶的位置,刚好就是栈中有效数据个数int capacity;//栈的空间大小
}ST;//初始化
void STInit(ST* ps)
{ps->arr = NULL;ps->top = ps->capacity = 0;
}//销毁
void STDesTroy(ST* ps)
{//arr不能为空,为空的话都没有向操作系统中申请内存,就没有必要销毁了if (ps->arr)free(ps->arr);ps->arr = NULL;ps->capacity = ps->top = 0;
}//入栈---栈顶
void STPush(ST* ps, STDataType x)
{assert(ps);//判断空间是否足够if (ps->top == ps->capacity){//增容int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;//如果capacity为0,就给4,realloc第二个参数的单位为字节,这里要申请4个整型空间,而不是4个字节STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}ps->arr = tmp;ps->capacity = newCapacity;}//空间足够ps->arr[ps->top++] = x;
}//判断栈是否为空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}//出栈---栈顶
void STPop(ST* ps)
{assert(!STEmpty(ps));ps->top--;
}//取栈顶元素
STDataType STTop(ST* ps)
{assert(!STEmpty(ps));return ps->arr[ps->top - 1];
}//获取栈中有效元素个数
int STSize(ST* ps)
{assert(ps);return ps->top;
}
//------------------------------以上是栈结构的定义和常见的方法---------------------------typedef struct {ST pushST;ST popST;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* pq=(MyQueue*)malloc(sizeof(MyQueue));STInit(&pq->pushST);STInit(&pq->popST);return pq;
}//入队列
void myQueuePush(MyQueue* obj, int x) {//往pushST插入数据STPush(&obj->pushST,x);
}//出队列
int myQueuePop(MyQueue* obj) {//popST为空---将pushST(不为空)导入popSTif(STEmpty(&obj->popST)){while(!STEmpty(&obj->pushST)){//取栈顶,入popST,出栈STPush(&obj->popST,STTop(&obj->pushST));STPop(&obj->pushST);}}//popST不为空直接出数据int top=STTop(&obj->popST);STPop(&obj->popST);return top;
}//取队头
int myQueuePeek(MyQueue* obj) {//popST为空---将pushST(不为空)导入popSTif(STEmpty(&obj->popST)){while(!STEmpty(&obj->pushST)){//取栈顶,入popST,出栈STPush(&obj->popST,STTop(&obj->pushST));STPop(&obj->pushST);}}//popST不为空直接取数据int top=STTop(&obj->popST);return top;
}//两个栈实现一个队列,两个栈都为空,队列才可以为空
bool myQueueEmpty(MyQueue* obj) {return STEmpty(&obj->popST) && STEmpty(&obj->pushST);
}void myQueueFree(MyQueue* obj) {STDesTroy(&obj->popST);STDesTroy(&obj->pushST);free(obj);obj=NULL;
}/*** 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);
*/