前言
座右铭:talk is easy,show me the code.
我们生活在幸福的时代,我们都站在巨人的肩膀上看世界
队列
我们可以把队列想象成一个排队的过程,先去排队的先服务,也即是“先进先出”。
队列的分类
1.链式队列
2.循环队列
也就是队列的实现可以用两种方式实现,一种是用链表实现,另外一种是利用数组实现,今天我们只讲解如何利用数组实现。
循环队列
入队:排队的时候又来一个人排队。类似于你现在要去食堂排队买食物,你需要排列在队列的最后面。
出队:正在排队的人得到服务,服务完成离开队列。类似于你买食物完成,离开队列去食用。
首先我们先抛出一个观念:用数组实现的队列必然是循环队列,如果不是这样的,那么出队过的数组单元因为再无法利用而浪费掉了。
定义循环队列的结构体
#define MAX 5//表示队列最大长度
//实际上最大可容纳元素为MAX-1,后面我们会讲到
typedef struct Node
{
int *p;
int front;//指向队列第一个元素
int rear;//指向队列最后一个元素的后一个空间
} Queue,*PQueue;
假如现在队列有三个元素,如图所示front,和rear的指向
我们初始化r让 rear=0,front=0;
我们可能理所当然觉得
入队的时候:rear=rear+1;
出队的时候:front=front+1;
但是这样没有考虑到可以对出队之后数组空间的利用。如下图所示:
所以,
入队:rear=(rear+1)%数组的长度
出队:front=(front+1)%数组的长度
队列为空或者为满的情况
显然,当rear=front=0的时候队列为空,当队列先入队,再出队,队列为空,此时rear=front=1,依次类推,我们可以得出结论 当rear=front的时候,队列为空
观察下图,我们可能不假思索的认为 当rear=front的时候队列为满。这时候可能就会出现歧义,当rear=front既可以是队列为满,也可以是队列为空,显然这样是不行的。
这样有两种方法解决,一种是定义一个变量,来记录队列中有多少个元素,但是我们通常不使用这种方法。我们通常使用另外一种方法,当(rear+1)%数组长度=front 的时候,数组满了。这样做有一个弊端,就是可以利用的数组空间是 数组长度-1 。
因此,数组长度为5,队列满的情况之一为下图
此时 (rear+1)%5=front,队列为满,数组长度为5,可是只存放了4个元素,但是当数组长度足够大的时候,循环链表的这个缺点几乎可以被忽略。
用代码实现队列
队列的初始化
申请动态内存,指定数组的大小,初始化front和rear,使之都指向数组下标为0位置
void init_queue(PQueue pq)
{
pq->p=(int *)malloc(MAX*sizeof(int));
pq->front=0;
pq->rear=0;
}
入队
为了示程序更加健壮,定义了bool full_queue(PQueue pq)函数,用来判断队列是否满了
//判断队列是否满了
bool full_queue(PQueue pq)
{
if((pq->rear+1)%MAX==pq->front)
return true;//队列满
else false;//没有满
}
//向队列里面写入入队元素的值
bool en_queue(PQueue pq,int val)
{
if(full_queue(pq))
{
return false;
}
else
{
pq->p[pq->rear]=val;
pq->rear=(pq->rear+1)%MAX;
return true;
}
}
出队
为了示程序更加健壮,定义了bool empty_queue(PQueue pq))函数。用来判断队列是否为空
//判断队列是否为空
bool empty_queue(PQueue pq)
{
if(pq->rear==pq->front)
{
return true;//队列空
}
else return false;
//队列没有空
}
//出队,指针用来传递即将出队元素的值
bool out_queue(PQueue pq,int *val)
{
if(empty_queue(pq))
{
return false;
}
else
{
*val=pq->p[pq->front];
pq->front=(pq->front+1)%MAX;
}
}
遍历队列
将队列里面所有的元素,从队首到队尾依次输出。
void travarse_queue(PQueue pq)
{
int i=pq->front;
while(i!=pq->rear)
{
printf("%d ",pq->p[i]);
i=(i+1)%MAX;
}
printf("\n");
}
结果演示
我们把上述函数通过放进主函数看一下效果
```c
int main()
{
Queue Q;
int i;
init_queue(&Q);
en_queue(&Q,1);//1号元素入队
en_queue(&Q,2);
en_queue(&Q,3);
en_queue(&Q,4);
en_queue(&Q,5);
travarse_queue(&Q);
//输出所有元素
if(out_queue(&Q,&i))
//如果队列不为,显示出队元素
{
printf("出队成功:%d\n",i);
}
travarse_queue(&Q);
return 0;
}
输出结果:
结语
理解了队列为空和为满的情况,循环队列自然迎刃而解。
个人博客:https:xuwenxiang666.github.io
欢迎你的到来
由于水平有限,本博客难免有不足,恳请各位不吝赐教!