常用数据结构 ——— 队列(环形队列和顺序队列)
目录
一、队列简介
二、顺序队列
三、环形队列
四、环形队列代码
1、队列结构体
2、队列初始化
3、判断队列是否为满
4、判断队列是否为空
5、将数据插入到队列中
6、读取队列中的数据
7、释放队列空间
8、功能测试
一、队列简介
队列只允许在队列头(front)进行删除操作,在队列尾(rear)进行插入操作,当队列中没有元素时,称为空队列。在队列中插入元素称为入队,从队列中删除元素称为出队。因为队列只允许在尾端插入,在头端删除,所以只有最早进入队列的元素才能最先从队列中删除,即队列有先进先出的特点。
二、顺序队列
即仅在队头进行删除在队尾进行插入,可用地址连续的存储单元依次存放队列中的数据,比如数组。队头和队尾的位置是变化的,所以要设置头、尾指针。
初始化时的头尾指针,均置为 0。 当头尾指针相等时队列为空或者为满,在非空队列里,头指针始终指向队头元素,尾指针始终指向队尾元素的下一位置。
由队列的原理可以将头指针当做读操作,将尾指针当做写操作,即在尾端插入数据就是写入队列,在头端删除数据就是将队列中的数据读出,这样好理解点。
刚开始头指针和尾指针都在同一位置
当队列入队时,尾指针加一,头指针保持不变,a1入队,尾指针rear+1指向下一个地址空间,即尾指针始终指向队尾的下一地址,如a4入队后,尾指针rear+1 。
队列出队时,尾指针保持不变,头指针依次加1,由先进先出原则,a1先入队,则a1先被读走,然后front+1,指向了 a2,a2删除后,front+1指向了 a3。
当a5删除后,头指针和尾指针的指向又相同相等了,即说明队列中的数据 已经全部读走
在顺序队列中,当尾指针已经指向了队列的最后一个位置的下一位置时,如果再有元素入队,就会发生“溢出”,此时队列中已经填满了数据,头指针还在开始位置。
顺序队列的 “假溢出” :即队列的存储空间并未填满,却发生了溢出。
比如 rear 现在指向了最后一个位置的下一位置,按照上面所说此时队列已经被填满,如果再有元素入队,就会发生“溢出”,但这是在头指针没有移动的前提下,如果之前队列头也删除了一些元素,那么队列头指针经过n次的 +1 之后,会遗留下了很多空地址,但是顺序队列就会认为再有元素入队,就溢出,即出现 “假溢出” 现象,这是不合理的,故出现了环形队列。
三、环形队列
环形队列的使用场景还是挺多的,比如要将单片机一些模块采集的数据连续上传到PC端,这里就可以用到环形队列,即将采集的数据放到队列中去,再将队列中的数据读出上传到PC端,这里为什么不直接将采集端和上传端直接相连呢?因为采集数据的速度和上传数据的速度是不知道的,如果直接相连会出错。
环形队列的原理就是将新元素加入到第一个位置上,构成类似于一个环一样的队列,入队和出队还是按照“先进先出”的原则进行,环形队列的空间利用率高。
环形队列解决了顺序队列 “假溢出” 的现象,但是又出现新的问题,即怎么判断队列是否为空,如果单用 rear = front 判断空或满显然是不行的,比如
此时两种情况都是 rear = front 的情况,在环形队列中,当队列满了之后 rear + 1会指向第一个地址,即出现了 rear = front 的情况。
一般判断队列空的条件是 rear = front, 通常少用一个元素的储存空间用来判断队列是否满,即在入队前测试尾指针加 1 后是否等于头指针,若相等则认为队满。
或者当用数组array[len]来表示队列时,则可用(rear - front)的差和数组长度 len 进行比较,如果相等则说明队列已满,(在下面说明这种方法)。
四、环形队列代码
W等于尾指针rear,R等于头指针front,相当于写操作和读操作。
1、队列结构体
/*队列结构体*/
typedef struct ring_buff{int array[len]; int W;int R;
}*ring;
2、队列初始化
/*队列初始化*/
struct ring_buff *fifo_init(void)
{struct ring_buff *p = NULL;p = (struct ring_buff *)malloc(sizeof(struct ring_buff));if(p == NULL){printf("malloc error\n");return -1;}else{p->W = 0;p->R = 0;memset(p->array,0,sizeof(p->array));return p;}
}
将队列相应空间清零。
3、判断队列是否为满
/*判断是否满*/
int get_ring_buff_fullstate(struct ring_buff *P_ring_buff)
{if((P_ring_buff->W - P_ring_buff->R) == len){return 1;}else{return 0;}
}
如上图所示,array[6] 的存储空间为array[0] - array[5],即6个数,当R和W等于0时指向array[0],存入数据后W++,指向下一个地址,当W将array[5]存入数据后会自加一,此时W = 6,R = 0,下一次判断队列是否满时条件成立,即W - R = len,len为数组长度6。
4、判断队列是否为空
/*判断是否为空*/
int get_ring_buff_emptystate(struct ring_buff *P_ring_buff)
{if(P_ring_buff->W == P_ring_buff->R){return 1;}else{return 0;}
}
当头指针和尾指针相等时判断为空
5、将数据插入到队列中
/*插入数据*/
int ring_buff_insert(struct ring_buff *P_ring_buff,int data)
{if(P_ring_buff == NULL){ printf("insert P_ring_buff error\n");return -1;}/*判断队列是否满*/if(get_ring_buff_fullstate(P_ring_buff) == 1){printf("full\n");return -1;}P_ring_buff->array[P_ring_buff->W%len] = data;P_ring_buff->W++;return 0;
}
W = {0、1、2、3、4、5 },则array[W%len] = {0、1、2、3、4、5},刚好依次对应,当W = 6时,6 % 6 = 0,又从array[0]开始存储数据,这也是环形队列的关键,即形成闭环。
6、读取队列中的数据
/*读取数据*/
int ring_buff_get(struct ring_buff *P_ring_buff)
{int data = 0;if(P_ring_buff == NULL){printf("get P_ring_buff error\n");return -1;}data = P_ring_buff->array[P_ring_buff->R%len];P_ring_buff->R++;return data;
}
读取数据和写入数据类似,也是当R = 6时,6 % 6 = 0,又从array[0]开始读取数据
7、释放队列空间
/*销毁*/
int ring_buff_destory(struct ring_buff *P_ring_buff)
{if(P_ring_buff == NULL){printf("destory P_ring_buff error\n");return -1;}free(P_ring_buff);return 0;
}
8、功能测试
#define len 6
int main()
{int i;int getData = 0;
/*初始化队列*/ring Pt_ring_buff = fifo_init();
/*向队列中写数据,即0 - 5*/for(i = 0;i < 6;i++){ring_buff_insert(Pt_ring_buff,i);}
/*将写入的数据读出三个,由先进先出原则应该读的0 - 2*/for(i = 0;i < 3;i++){printf(" %d",ring_buff_get(Pt_ring_buff));}printf("\n");
/*再写入三个数据,此时写入的数据应该在上面的数据之后,即在5之后*/for(i = 8;i < 11;i++){ring_buff_insert(Pt_ring_buff,i);}
/*读取队列中的数据,此时再次读取队列中的数据时,0 - 2 已经被读走,所以应该是从3、4、5、8、9、10、3 ...循环读取十个数据*/ for(i = 0;i < 10;i++){printf(" %d",ring_buff_get(Pt_ring_buff));}ring_buff_destory(Pt_ring_buff); //释放空间printf("\n");system("pause");return 0;
}
输出结果
常用数据结构 ——— 队列(环形队列和顺序队列)相关推荐
- 数据结构之基于Java的顺序队列实现
本文的代码来自于<数据结构与算法(JAVA语言版)>,是笔者在网上找到的资料,非正式出刊版物.笔者对代码一些比较难以理解的部分添加了注释和图解,欢迎大家来讨论. 重点理解通过取余运算将线性 ...
- java编程 队列_5.1、顺序队列(java实现)
public classSeqQueue {private final int MaxSize = 8;private int rear; //队尾指针 private int front; //队头 ...
- Java数据结构(1.1):数据结构入门+线性表、算法时间复杂度与空间复杂度、线性表、顺序表、单双链表实现、Java线性表、栈、队列、Java栈与队列。
数据结构与算法入门 问题1:为什么要学习数据结构 如果说学习语文的最终目的是写小说的话,那么能不能在识字.组词.造句后就直接写小说了,肯定是不行的, 中间还有一个必经的阶段:就是写作 ...
- 数据结构(二):线性表包括顺序存储结构(顺序表、顺序队列和顺序栈)和链式存储结构(链表、链队列和链栈)...
还记得数据结构这个经典的分类图吧: 今天主要关注一下线性表. 什么是线性表 线性表的划分是从数据的逻辑结构上进行的.线性指的是在数据的逻辑结构上是线性的.即在数据元素的非空有限集中 (1) 存在唯一的 ...
- 队列(常用数据结构之一)
队列 队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表.进行插入操作的端称为队尾,进行删除 ...
- C语言数据结构-第三章栈和队列-电大同步进度
第三章栈和队列简介 从数据结构角度看,栈和队列是两种重要的线性结构,是一类操作受限制的特殊线性表,其特殊性在于限制插入和删除等运算的位置. 堆栈,限制用户只能在指定的一端插入和删除元素,因此具有后进先 ...
- c语言建立队列(顺序队列、循化队列和链式队列)
c语言建立队列 一.顺序队列 队列的顺序存储结构 顺序队列的讨论 "下溢"现象 "真上溢"现象 "假上溢"现象 二.如何解决"假上 ...
- 数据结构Python版(四)——队列
目录 一.队列简介 二.顺序队列 2.1 非循环队列 2.2 循环队列 2.2.1 假溢出 2.2.2 循环队列的架构 2.2.3 循环队列的实现 三.链队 3.1 链队的完整实现 四.双端队列 4. ...
- (PTA)数据结构(作业)6、队列
栈是后进先出的线性表(Last In First Out,LIFO),插入和删除的操作都在栈顶进行. 队列是先进先出的线性表(First In First Out,FIFO),插入在队尾进行,删除在队 ...
最新文章
- 第一篇:时间和全局状态
- 数据系列:如何在Windows Azure虚拟机上设置SQL Server
- python的with用法(参考)
- 三面腾讯,竟然挂在了JVM上…
- android中变量作用域,在 Android 和 Hilt 中限定作用域
- AM335X 分配大于4M的framebuffer
- 滴滴笔试准备 项目分配利益最大化
- 初始化对于类与接口的异同点深入解析
- SDNU 1170.津津的储蓄计划
- mysql_affected_rows()、mysql_fetch_row、mysql_fetch_assoc
- javaee7实现websocket_websocket协议,tcp分包与粘包解决
- 药企如何应对计算机系统验证?浪潮GMP管理保驾护航
- 笔记本电脑里计算机未响应,浅析笔记本win7系统下Word程序总是未响应的原因及解决办法【图文】...
- ORACLE通过身份证号计算年龄
- 常见手机病毒学习总结
- 问答网站Stack Overflow的成功之道
- 线程安全问题和解决方法
- 修改mac地址导致计算机无法上网,win7系统更换MAC地址解决无法连接网络问题的解决方法...
- C4D模型工具—优化
- 由浅入深学习Flash制作赛车游戏教程