赞
踩
引言:这篇文章的末尾有完整的实现代码,前面还是先进行分步实现,即我们探讨一下为什么要这样做,以及我们应该怎么样一步一步的实现循环队列。
目录
我们可以把队列理解为食堂的排队买饭,我们只能在队尾进行排队(入队操作),然后队头的同学买完饭走了(出队操作)。所以对于队的理解就很清楚了,队就是一个只允许在队头进行出队操作,在队尾进行入队操作。即队是一个先进先出的表。(FIFO)
(1)、队的初始化
(2)、判断队是否为空
(3)、求队列的长度
(4)、入队操作
(5)、出队操作
(6)、求队首元素
(1)、我们首先用front和rear来标记当前队列的队首的前一个位置和队尾元素。
(2)、判断对空,那就是front和rear都标记为同一个位置。
(3)、理解这段话:那我们如何判断队满,假如说我们让这个队列一直进行入队操作,那么我们是否可以说当rear标记的位置为Maxsize-1(因为数组下标是从0开始的,Maxsize-1代表最后一个位置)时,队列就满了呢?当然不可以这样,因为我们的队首可以进行出队操作,当一直出队直到标记位为rear的标记位时,这时队列并不是队满的状态,刚好是队空。所以我们要想一个办法改变这种情况。由此引出来循环队列,我们可以把这个队设置成循环队列,这样的话就可以一直转圈的入队和出队。那我们如何判断队满呢?式子((rear+1)%Maxsize==front),若成立则说明队满。我们可以分析一下为什么这样因为front是标记队首元素的前一个,rear是指向队尾元素,(rear+1)%Masize的意思是防止rear指向最后一个位置(Maxsize-1),当它再加1的时候,就是Maxsize了,已经超过了数组的最大下标,而如果我们再对Maxsize取余的话呢,当rear+1变为Maxsize之后再对Maxsize取余就变为了0,又回到了队列的首位置,所以我们这样做是有必要的。(rear+1)%Maxsize==front避免了rear会超出对大范围,当rear的下一个为front的时候,队就满了,因为我们是空出来了一个位置将front指向它,即front指向队首元素的前一个位置,这个位置并不存放东西。(rear+1)%Maxsize或者是(front+1)%Maxsize他们%Maxsize这个操作都是为了将当rear或者是front+1之后指向Maisize这个位置时,把它转换为0。
首先声明一个队列结构体
- #include <stdio.h>
- #include <stdlib.h>
- #define Maxsize 5
- //顺序队列的实现
- //重新定义数据类型,typedef在这里的意思就是重新定义它后面的东西的别名
- typedef int ElemType;//这句话的意思就是定义int的别名为ElemType来代替int
- //声明一个结构体
- typedef struct Queue
- {
- ElemType data[Maxsize];//队列能存多少元素
- int front,rear; //front指向队列的前一个元素,rear指向队列的最后一个元素,即队尾
- }SqQueue; //重新定义结构体的名字为SqQueue
- //先进行初始化操作
- void Init(SqQueue *s)
- {
- s->front=s->rear=0; //将队首和队尾标记队列相同的位置
- }
- //判断队列是否为空
- int Empty(SqQueue s)
- {
- if(s.front==s.rear) //因为我们在初始化的时候将它们两个相等了,所以判空直接判断
- return 1; //为空返回真
- else
- return 0; //不为空返回假,程序中除了0全为真
- }
求队列的长度,我们首先判断队列是否为空,如果不为空,判断rear是否大于front,若rear大于front直接相减即可,若rear小于front,相减之后为负数,再加上一个Maxsize即可,如果相减之后为正数,那么我们可以加上一个Maxsize再取余Maxsize即可,这样的话,不管rear是否发育front,我们都可以用(s.rear-s.front+Maxsize)%Maxsize来表示
- //求队列的长度
- int Length(SqQueue s)
- {
- //先判断队列是否为空
- if(Empty(s)) //意思是如果队列为空则返回1,那么if括号里面的意思是不等于0的话执行里面的东西
- {
- return 0;
- }
- return (s.rear-s.front+Maxsize)%Maxsize;
- }
- //入队操作
- void Add(SqQueue *s,ElemType x)//将x入队
- {
- //首先判断队列是否已满
- if(s->front==(s->rear+1)%Maxsize) //队列中留出一个空位置让front指向它,那么当rear+1等于front的话我们就说队满了
- {
- printf("当前队列已满,不能将值为:%d的元素入队\n\n",x);
- return;
- }
- else
- {
- s->data[(s->rear+1)%Maxsize]=x;//在rear的下一个位置存入元素x
- s->rear=(s->rear+1)%Maxsize; //把rear的位置往后移一位
- }
- }
- //出队操作
- void Dele(SqQueue *s,ElemType *e) //用e来保存出队的元素
- {
- if(Empty(*s))
- {
- printf("当前队列为空,操作失败\n\n");
- return;
- }
- else
- {
- *e=s->data[(s->front+1)%Maxsize];//用e来保存出队的这个元素
- s->front=(s->front+1)%Maxsize; //出队之后front往后移动一位
- }
- }
- //读取队首元素
- ElemType Get(SqQueue s)
- {
- if(Empty(s)) //意思是如果队列为空则返回1,那么if括号里面的意思是不等于0的话执行里面的东西
- {
- printf("队首元素不存在,队列为空\n\n");
- return 0;
- }
- return s.data[(s.front+1)%Maxsize];//返回队首元素,这样做的目的是防止front当前的位置在Maxsize这个位置
- }
- int main()
- {
- SqQueue s;//定义一个队,名称s;这里也可以定义一个队指针,用这个指针来代替这个表s,修改一下函数中的参数就行。只是实现方式不同,结果相同
- //进行初始化
- Init(&s);
- ElemType e=0;
- int x;
- printf("先将队列初始化之后的头标记为:%d 尾标记为:%d\n\n",s.front,s.rear);
- printf("队列的大小为:%d\n\n",Maxsize);
- //来五次入队操作
- Add(&s,8);
- Add(&s,5);
- Add(&s,4);
- Add(&s,0);
- Add(&s,7);
- //看一下当前队的长度
- x=Length(s);
- if(x)
- {
- printf("操作完成之后,当前队列的长度为:%d\n\n",Length(s));
- }
- //读取队首元素
- x=Get(s);
- if(x) //如果x不为0,执行里面的东西
- {
- printf("当前队列中的队首元素为:%d\n\n",x);
- }
- //出队操作
- Dele(&s,&e);
- Dele(&s,&e);
- Dele(&s,&e);
- //读取队首元素
- x=Get(s);
- if(!(x==0&&e==0)) //如果x和e不为0,执行里面的东西
- {
- printf("出队操作之后,刚刚出队的元素为:%d,当前队首元素为:%d\n\n",e,x);
- }
- return 0;
- }
- #include <stdio.h>
- #include <stdlib.h>
- #define Maxsize 5
- //顺序队列的实现
- //重新定义数据类型,typedef在这里的意思就是重新定义它后面的东西的别名
- typedef int ElemType;//这句话的意思就是定义int的别名为ElemType来代替int
- //声明一个结构体
- typedef struct Queue
- {
- ElemType data[Maxsize];//队列能存多少元素
- int front,rear; //front指向队列的前一个元素,rear指向队列的最后一个元素,即队尾
- }SqQueue; //重新定义结构体的名字为SqQueue
- //先进行初始化操作
- void Init(SqQueue *s)
- {
- s->front=s->rear=0; //将队首和队尾标记队列相同的位置
- }
- //判断队列是否为空
- int Empty(SqQueue s)
- {
- if(s.front==s.rear) //因为我们在初始化的时候将它们两个相等了,所以判空直接判断
- return 1; //为空返回真
- else
- return 0; //不为空返回假,程序中除了0全为真
- }
- //求队列的长度
- int Length(SqQueue s)
- {
- //先判断队列是否为空
- if(Empty(s)) //意思是如果队列为空则返回1,那么if括号里面的意思是不等于0的话执行里面的东西
- {
- return 0;
- }
- return (s.rear-s.front+Maxsize)%Maxsize;
- }
- //读取队首元素
- ElemType Get(SqQueue s)
- {
- if(Empty(s)) //意思是如果队列为空则返回1,那么if括号里面的意思是不等于0的话执行里面的东西
- {
- printf("队首元素不存在,队列为空\n\n");
- return 0;
- }
- return s.data[(s.front+1)%Maxsize];//返回队首元素,这样做的目的是防止front当前的位置在Maxsize这个位置
- }
- //入队操作
- void Add(SqQueue *s,ElemType x)//将x入队
- {
- //首先判断队列是否已满
- if(s->front==(s->rear+1)%Maxsize) //对列中留出一个空位置让front指向它,那么当rear+1等于front的话我们就说队满了
- {
- printf("当前队列已满,不能将值为:%d的元素入队\n\n",x);
- return;
- }
- else
- {
- s->data[(s->rear+1)%Maxsize]=x;//在rear的下一个位置存入元素x
- s->rear=(s->rear+1)%Maxsize; //把rear的位置往后移一位
- }
- }
- //出队操作
- void Dele(SqQueue *s,ElemType *e) //用e来保存出队的元素
- {
- if(Empty(*s))
- {
- printf("当前队列为空,操作失败\n\n");
- return;
- }
- else
- {
- *e=s->data[(s->front+1)%Maxsize];
- s->front=(s->front+1)%Maxsize;
- }
- }
- int main()
- {
- SqQueue s;//定义一个队,名称s;这里也可以定义一个队指针,用这个指针来代替这个表s,修改一下函数中的参数就行。只是实现方式不同,结果相同
- //进行初始化
- Init(&s);
- ElemType e=0;
- int x;
- printf("先将队列初始化之后的头标记为:%d 尾标记为:%d\n\n",s.front,s.rear);
- printf("队列的大小为:%d\n\n",Maxsize);
- //来五次入队操作
- Add(&s,8);
- Add(&s,5);
- Add(&s,4);
- Add(&s,0);
- Add(&s,7);
- //看一下当前队的长度
- x=Length(s);
- if(x)
- {
- printf("操作完成之后,当前队列的长度为:%d\n\n",Length(s));
- }
- //读取队首元素
- x=Get(s);
- if(x) //如果x不为0,执行里面的东西
- {
- printf("当前队列中的队首元素为:%d\n\n",x);
- }
- //出队操作
- Dele(&s,&e);
- Dele(&s,&e);
- Dele(&s,&e);
- x=Get(s);
- if(!(x==0&&e==0))
- {
- printf("出队操作之后,刚刚出队的元素为:%d,当前队首元素为:%d\n\n",e,x);
- }
-
- return 0;
- }
循环队列的难点就是如何判断队空和队满,以及当rear指向最后一个位置时,我们再进行入队的操作,还有当front指向最后一个位置,我们再进行出队的操作,都需要队Maxsize进行取模运算,顺序表,链表,栈,队他们的操作都很相似,大家可以对比一下,只要掌握了其中一个的操作,对于其他的操作,都可以迎刃而解,将逻辑内化于心。本人能力有限,如有表述不对的地方,欢迎批评指正。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。