1.什么是(顺序)队列
队列是一种特殊的线性表(物理空间地址连续存储,指针类型正相反),特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头,是先进先出FIFO形式。
线性表中就包括数组,所以这里使用数组来完成队列的数据存取;这里先讲解顺序队列
例图:长度为8的数组
上面是队列空时,头尾指向的位置是一样的head=tail;
当数据存储时,head保持不变,tail向后移动,则1是先存进去,然后是2,最后是3存进去;
数据读取时,head向后移动,tail保持不变,1先被读取,然后是2,最后是3;
这里只介绍这些用到的参数,关于存满或溢出等参数其它可以自行百度
2.什么是环形队列
原因:更好管理队列,更好的判断队列空或满
循环队列也是用数组来构建,只不过经过特别算法,使得头尾内存上实现连接
存取数据仍是一样:
当数据存储时,head保持不变,tail向后移动,则1是先存进去,然后是2,最后是3存进去;
数据读取时,head向后移动,tail保持不变,1先被读取,然后是2,最后是3;
提示:无论是顺序队列还是循环队列,tail一直指向的是空位置
3.实际重要的是如何判断循环队列空满?:
空判断:head=tail指向,队列无数据
满判断:head=tail指向,队列有数据
由上可知,无论队列是空是满,都存在head=tail;那如何区分呢?
网上有说, 判断队列空用 head=tail
判断队列满用front=(rear+1)%MaxSize
我不大习惯用这个,这个还会有一个空间用不了,浪费;而是单独标志变量flag来标识数据进出:写入数据flag=1,读出数据flag=0;
空时:head=tail && flag=0
满时:head=tail && flag=1
4.环形队列存取数据原理步骤
(1)先判断循环队列是否满,如果满则输出提示信息,或者按照设计进行从头覆盖处理;
一般来说,实际串口通信时,不可能存满的,如果有存满标志说明是程序设计错误;
(2)如果不满则开始逐个字节存入数据,队列tail尾指向向下移动(数组下标加1),存入标志置flag=1
(3)读数据时,先判断数据是否为空,如果空则不读取了;如果不空,则head指向向下移动,开始从数组中读取数据,head对应的数组下标也加1,读取标志清flag=0
(4)判断head是否等于tail,同时判断falg标志,最后判断是否为空,为空时说明数据已经完全读取了
5.环形队列存取数据代码实验
#include "stdio.h"
/*-------------------------环形队列------------------------------------------*/
typedef unsigned char u8;
typedef unsigned short int u16;
#define size 8 //环形队列大小
u8 Table[size]={0}; //环形队列
typedef struct
{
u8 head;//头
u8 tail;//尾
u8 flag;//满标志
}Queue_InitTypeDef;
int main(void)
{
u8 a,b,i;
char InOut=' ';
Queue_InitTypeDef Queue_InitStre={0};//结构体元素全部清0
Queue_InitTypeDef * Queue=NULL;
Queue=&Queue_InitStre;
Queue->flag=0;
Queue->head=0;
Queue->tail=0;
while(1)
{
if(InOut==' ')
{
printf("请输入指令 i是入数据 o是出数据:");//提示选择功能
scanf("%c",&InOut);//
printf("InOut=%c\r\n",InOut);//
}
else if(InOut=='i')//写入
{
if((Queue->head==Queue->tail)&&(Queue->flag==1))//满判断
{
printf("队列存满\r\n");
for(i=0;i<size;i++)
{
printf("val=%d",Table[i]);//打印数据
}
InOut='o';//自动转为输出
printf("自动转为输出\r\n");
}
else//非满
{
printf("请输入数据:");//提示
scanf("%d",&a);//入数据
printf("a=%d\r\n",a);//入数据
Table[Queue->tail]=a;//数据处理
Queue->tail=(Queue->tail+1)%size;//tail指向向后移动
Queue->flag=1;//写入时标志清0
printf("head=%d tail=%d flag=%d\r\n",Queue->head,Queue->tail,Queue->flag);//输出head,tail,flag
#if 1 //调试用-不存满实验只存5个字节
if(Queue->tail==5)
{
InOut='o';//自动转为输入
printf("自动转为输出\r\n");
}
#endif
}
}
else if(InOut=='o')//读取
{
if((Queue->head==Queue->tail)&&(Queue->flag==0))//空判断
{
printf("head=%d tail=%d flag=%d\r\n",Queue->head,Queue->tail,Queue->flag);//输出head,tail,flag
printf("队列为空\r\n");
Queue->head=0;//从头再来,有 没有存满时读取的情况
Queue->tail=0;//从头再来,有 没有存满时读取的情况
InOut='i';//自动转为输入
printf("自动转为输入\r\n");
}
else//非空
{
b=Table[Queue->head];//出数据
Queue->head=(Queue->head+1)%size;head指向向后移动
Queue->flag=0;//读取时标志清0
printf("b=%d\r\n",b);//打印读取的数据
printf("head=%d tail=%d flag=%d\r\n",Queue->head,Queue->tail,Queue->flag);//输出head,tail,flag
}
}
else
{
InOut=' ';
}
}
return 0;
}
测试结果:队列长度是5