这里的 FIFO 是先入先出的意思,即谁先进入队列,谁先出去。比如我们需要串口打印数据,当使用缓存将该数据保存的时候,在输出数据时必然是先进入的数据先出去,那么该如何实现这种机制呢?

首先就是建立一个缓存空间,这里假设为 7 个字节空间进行说明。

缓存一开始没有数据,并且用一个变量 rear 指示下一个存入缓存的索引地址,这里下一个存放的位置就是 0,用另一个变量 front 指示下一个存入缓存的索引地址,并且下一个读出数据的索引地址也是 0。目前队列中是没有数据的,也就是不能读出数据,队列为空的判断条件在这里就是两个索引值相同。

现在开始存放数据:

在这里可以看到队列中加入了 5 个数据,并且每加入一个数据后队尾索引加 1,队头不变,这就是数据加入队列的过程。但是缓存空间只有 7 个,如何判断队列已满呢?

如果只是先一次性加数据到队列中,然后再读出数据,那这里的判断条件显然是队尾索引为 6,但实际上是在加入数据的同时也可能出现有数据已出队的情况,比如:

这个时候索引是 6,但是实际上还是有一个索引为 0 的位置是空的,也就是实际上还是可以再加入一个数据的。这个时候又该如何判断是否队列已满呢?

通过以下算法即可:

(rear + 1) % 7 == front

你可以发现这个算法的巧妙。通过%运算将索引又从 6 返回到了 0 处,这是实现循环队列的关键之处。通过该算法就能知道队列是否已满了。队列空的算法就是队头队尾索引相同。

front == rear

刚才说过通过%运算可以实现索引值的循环,所以当索引为 6 的时候,一般思维是通过 if 判断语句将其定位到下一个索引位置,而这里通过以下算法即可将其重新定位:

rear = (rear + 1) %7

这样当 rear 等于 6 的时候下一个索引就是 0 了。非常巧妙的实现了数值的循环。这个时候就出现了如下情况:

队尾索引跑到了队头索引的前头。并且周而复始,这就是循环队列了,充分的利用了空间。

但你有没有发现其实在有 7 个空间的情况下其实只能存放 6 个数据,另一个数据空间是没法使用的,为什么呢?看看以下两种情况:

这里一种为队列为空的情况,有一种队列已满的情况,这个时候到底是空还是满的单靠这两个变量是无法判断的,这个时候就需要增加一个变量指示队列已满的情况,并且需要加入判断语句,降低了运行效率,所以建议采用留空的方式进行统一处理。附上代码自行感受。

这样入队出队操作都有了,也就算完成了基本操作,实际上有时候需要获取整个队列存放的数量,这时又涉及到了一个有意思的公式:

(rear – front + 7)  %  7

来看一看这个公式的巧妙性。当出现如下 rear 在后,front 在前这种正常情况时,只要两种相减即可得到队列的长度。

但实际上对于循环队列来说 rear 在前,front 在后也是再正常不过的事情,如下:

这个时候又该如何获取呢?就是利用上面的公式了。通过它就能适应这两种情况。

通过了解这个公式,感受它的巧妙,又可以想到利用这个公式干点其他的,比如在时间的获取上,不管你计时变量设置得多么大,总有一个限度,总会出现计时溢出的情况,但实际上你只要获取溢出时间内的时间即可,比如一个 16 位变量,每 1ms 自加 1,你想获取 100ms 的定时时间(小于 65535),正常情况下只需通过如下判断即可准确获取:

CurrentTime >= (Time + 100)

CurrentTime 是变化的时间,Time 是开始的时刻。但你开始的时刻是有可能是在 CurrentTime = 65435 的情况下的,CurrentTime 必然溢出,开始从零开始计时,这样你这个条件满足必须是 CurrentTime = 65535,也就是说你从 65435 – 0 - 65535,整整多了一个溢出周期时间。而如果你使用上面的公式就即使计数器溢出了,也能获取准确的定时时间。

(CurrentTime  -  Time + 65535)  % 65535  >= 100

利用如下算法验证:

结果如下:

(实际上,这种使用一个整型数的最大值来计算不需要这么麻烦,可以直接简单的 if(CurrentTime - Time + 65536 >100)即可)

还有一种方法就是利用无符号减法的特性来获取,自行研究即可。验证代码如下:

结果如下:



有一种功能需求可能是覆盖最旧的数据,也就是说缓存区中始终保留最近的数据,而将最旧的数据删除掉,如何实现呢?通过学习循环队列,可以从中得到启发。就是通过%运算将数据始终循环保存在缓存中,在不需要判断是否队列已满的情况下继续入队就可以实现将最旧的数据覆盖了。这是我在做一个项目的时候想的,想过用队列,想过用链表,也想过用栈,到头来发现其实没那么复杂,幸好之前有看过循环队列的源码,从中得到很多启发。在这个项目中还利用了一个小技巧,这是我从学习文件系统得到的启发。那就是如果入队的单个元素比较多,一个元素有 100byte,如下:

你是否就是将所有的 7*100 个字节数据进行删除呢?那你的效率也是够低的,写入数据的时候没办法,必须一个个准确写入,但删除的时候也需要如此吗?看如下处理:

只要队列的每个元素设置一个标志,删除这个标志就代表这个队列元素已删除即可,而插入元素则就重新设置该标志,表明你已经存放了数据,并将数据写入对应的位置即可。当然这个标志其实还可以用于标志这个元素属于什么种类的数据,这样就是将两种功能结合了在一个标志内了,而你要做的就是实现他们之间的一一对应关系即可。

-----------------------------------------------------------------------------------------2018-08-08 Osprey

获取最新笔记,欢迎关注公众号:鱼鹰谈单片机

一文看懂队列(FIFO)相关推荐

  1. 一文看懂JUC之AQS机制

     作者:VectorJin juejin.cn/post/6844904041760161806 为了解决原子性的问题,Java加入了锁机制,同时保证了可见性和顺序性.JDK1.5的并发包中新增了Lo ...

  2. 一文看懂Python collections模块的高效数据类型

    原作: George Seif, 发表于medium.com, 大江狗原创翻译, 并对原文稍作修改. Python的最大优势之一是其广泛的模块和软件包.这将Python的功能扩展到许多受欢迎的领域,包 ...

  3. php-fpm进程的用户组,一文看懂PHP进程管理器php-fpm

    php-fpm是什么 php-fpm是PHP的一个进程管理器.php下面的众多work进程皆有php-fpm进程管理器管理. php-fpm的工作原理 php-fpm全名是PHP FastCGI进程管 ...

  4. Linux的swap损耗固态寿命吗,一文看懂固态硬盘使用寿命问题

    原标题:一文看懂固态硬盘使用寿命问题 Dual-pool算法是比较经典的磨损平衡算法,目的是为了延长闪存的使用寿命.它实现了两方面解决:第一是存储冷数据来防止块被磨损,因为频繁更新的热数据会是磨损增加 ...

  5. 一文看懂 AI 训练集、验证集、测试集(附:分割方法+交叉验证)

    2019-12-20 20:01:00 数据在人工智能技术里是非常重要的!本篇文章将详细给大家介绍3种数据集:训练集.验证集.测试集. 同时还会介绍如何更合理的讲数据划分为3种数据集.最后给大家介绍一 ...

  6. 一文看懂计算机视觉-CV(基本原理+2大挑战+8大任务+4个应用)

    2020-03-06 20:00:00 计算机视觉(Computer Vision)是人工智能领域的一个重要分支.它的目的是:看懂图片里的内容. 本文将介绍计算机视觉的基本概念.实现原理.8 个任务和 ...

  7. 一文看懂人脸识别(4个特点+4个实现步骤+5个难点+算法发展轨迹)

    2020-03-09 20:01:00 人脸识别是身份识别的一种方式,目的就是要判断图片和视频中人脸的身份时什么. 本文将详细介绍人脸识别的4个特点.4个步骤.5个难点及算法的发展轨迹. 什么是人脸识 ...

  8. 一文看懂卷积神经网络-CNN(基本原理+独特价值+实际应用)

    http://blog.itpub.net/29829936/viewspace-2648775/ 2019-06-25 21:31:18 卷积神经网络 – CNN 最擅长的就是图片的处理.它受到人类 ...

  9. 【深度学习理论】一文看懂卷积神经网络

    [深度学习理论]一文看懂卷积神经网络 https://mp.weixin.qq.com/s/wzpMtMFkVDDH6scVcAdhlA 选自Medium 作者: Pranjal Yadav 经机器之 ...

最新文章

  1. leetcode 二分查找 Search in Rotated Sorted ArrayII
  2. python 解码json数据并在一个OrderdDict中保留其顺序
  3. 用css3的@keyframes里设置transform:rotate(); 当控制动画暂停:animation-play-state:paused暂停,在微信和safari里无效...
  4. python插值算法实现_图像插值算法Opencv+python实现
  5. 中英文对照 —— 哲学
  6. xUtils 中的BitmapUtils 全面注释
  7. 中信银行MySQL面试_【中信银行信用卡中心面试|面试题】-看准网
  8. FaceBook和Google广告API接口文档
  9. cubieboard 资源
  10. 购物车中我的订单查询
  11. linux系统宝塔安装nodejs,node安装,nodejs安装,Windows nodejs安装,Linux nodejs安装
  12. 使用DirectDraw直接显示YUV视频数据
  13. CSS的表格样式和列表样式
  14. 图像处理:分水岭算法(图像分割)
  15. Node课程(3,2,1,8,3)
  16. java开发工具包 jdk_什么是JDK? Java开发工具包简介
  17. 多麦克风做拾音的波束_【语音交互】先从麦克风阵列聊起
  18. PC免费简约开源的TXT小说阅读器(提取章节、书籍分组管理、记忆阅读进度、换肤、换字体、换主题)仅支持Windows
  19. MAC系统分区的目录结构
  20. Java毕设项目诊所信息管理系统(java+VUE+Mybatis+Maven+Mysql)

热门文章

  1. 网络安全的维护手段有哪些?
  2. Win7系统:分区助手5.2专业版实战使用截图【将D盘空间挪到C盘】--- 为体验安装VS2015
  3. 植物大战僵尸关卡金币存档修改过程
  4. 服务器被入侵如何排查?如何防止服务器被入侵?
  5. Navicat 多次试用期
  6. Linux中#!表示什么意思?
  7. Linux麒麟系统中文乱码,ubuntu麒麟系统tomcat中文乱码怎么办?ubuntu tomcat中文显示乱码解决方法...
  8. jmx_exporter 配置详解
  9. centos系统重置root密码,忘记密码修改
  10. dicom标注工具_四款常用的医学图像标注工具