什么是环形队列?

环形缓冲区是一个非常典型的数据结构,这种数据结构符合生产者,消费者模型,可以理解它是一个水坑,生产者不断的往里面灌水,消费者就不断的从里面取出水。

那就可能会有人问,既然需要灌水,又需要取出水,为什么还需要开辟一个缓冲区内存空间呢?直接把生产者水管的尾部接到消费者水管的头部不就好了,这样可以省空间啊。

答案是不行的,生产者生产水的速度是不知道的,消费者消费水的速度也是不知道的,如果你强制接在一起,因为生产和消费的速度不同,就非常可能存在水管爆炸的情况,你说这样危险不危险?

在音频系统框架下,alsa就是使用环形队列的,在生产者和消费者速度不匹配的时候,就会出现xrun的问题。

环形队列的特点

1、数组构造环形缓冲区

假设我们用数组来构造一个环形缓存区,如下图

我们需要几个东西来形容这个环形缓冲区,一个的读位置,一个是写位置,一个是环形缓冲区的长度

从图片看,我们知道,这个环形缓冲区的读写位置是指向数组的首地址的,环形缓冲区的长度是 5 。

那如何判断环形缓冲区为空呢?

如果 R == W  就是读写位置相同,则这个环形缓冲区为空

那如何判断环形缓冲区满了呢?

如果 (W - R )= Len ,则这个环形缓冲区已经满了。

2、向环形缓冲区写入 3个数据

写入 3 个数据后,W 的值等于 3 了,R 还是等于 0。

3个企鹅已经排列

3、从环形缓冲区读取2个数据

读出两个数据后,R = 2 了,这个时候,W还是等于 3,毕竟没有再写过数据了。

4、再写入3个数据

如果 W > LEN 后,怎么找到最开始的位置的呢?这个就需要进行运算了,W%LEN 的位置就是放入数据的位置 ,6%5 = 1。

5、再写入1个数据

这个时候环形队列已经满了,要是想再写入数据的话,就不行了,(W - R) = 5 == LEN

代码实现

/* 实现的最简单的ringbuff 有更多提升空间,可以留言说明 */

#include "stdio.h"

#include "stdlib.h"

#define LEN 10

/*环形队列结构体*/

typedef struct ring_buff{

int array[LEN];

int W;

int R;

}*ring;

/*环形队列初始化*/

struct ring_buff * fifo_init(void)

{

struct ring_buff * p = NULL;

p = (struct ring_buff *)malloc(sizeof(struct ring_buff));

if(p == NULL)

{

printf("fifo_init malloc error\n");

return NULL;

}

p->W = 0;

p->R = 0;

return p;

}

/*判断环形队列是否已经满了*/

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);

}

}

/*判断环形队列为空*/

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);

}

}

/*插入数据*/

int ring_buff_insert(struct ring_buff * p_ring_buff,int data)

{

if(p_ring_buff == NULL)

{

printf("p null\n");

return (-1);

}

if(get_ring_buff_fullstate(p_ring_buff) == 1)

{

printf("buff is full\n");

return (-2);

}

p_ring_buff->array[p_ring_buff->W%LEN] = data;

p_ring_buff->W ++;

//printf("inset:%d %d\n",data,p_ring_buff->W);

return (0);

}

/*读取环形队列数据*/

int ring_buff_get(struct ring_buff * p_ring_buff)

{

int data = 0;

if(p_ring_buff == NULL)

{

printf("p null\n");

return (-1);

}

if(get_ring_buff_emptystate(p_ring_buff) == 1)

{

printf("buff is empty\n");

return (-2);

}

data = p_ring_buff->array[p_ring_buff->R%LEN];

p_ring_buff->R++;

return data;

}

/*销毁*/

int ring_buff_destory(struct ring_buff * p_ring_buff)

{

if(p_ring_buff == NULL)

{

printf("p null\n");

return (-1);

}

free(p_ring_buff);

return (0);

}

int main()

{

int i = 0;

/*定义一个环形缓冲区*/

ring pt_ring_buff = fifo_init();

/*向环形缓冲区中写入数据*/

for(i = 0;i<10;i++)

{

ring_buff_insert(pt_ring_buff,i);

}

/*从环形缓冲区中读出数据*/

for(i = 0;i<10;i++)

{

printf("%d ",ring_buff_get(pt_ring_buff));

}

/*销毁一个环形缓冲区*/

ring_buff_destory(pt_ring_buff);

return (1);

}

换一个写法,这个写法是各种大神级别的

/* 实现的最简单的ringbuff 有更多提升空间,可以留言说明 */

#include "stdio.h"

#include "stdlib.h"

#define LEN 64

/*环形队列结构体*/

typedef struct ring_buff{

int array[LEN];

int W;

int R;

}*ring;

/*环形队列初始化*/

struct ring_buff * fifo_init(void)

{

struct ring_buff * p = NULL;

p = (struct ring_buff *)malloc(sizeof(struct ring_buff));

if(p == NULL)

{

printf("fifo_init malloc error\n");

return NULL;

}

p->W = 0;

p->R = 0;

return p;

}

/*判断环形队列是否已经满了*/

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);

}

}

/*判断环形队列为空*/

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);

}

}

/*插入数据*/

int ring_buff_insert(struct ring_buff * p_ring_buff,int data)

{

if(p_ring_buff == NULL)

{

printf("p null\n");

return (-1);

}

if(get_ring_buff_fullstate(p_ring_buff) == 1)

{

printf("buff is full\n");

return (-2);

}

//p_ring_buff->array[p_ring_buff->W%LEN] = data;

p_ring_buff->array[p_ring_buff->W&(LEN -1)] = data;

p_ring_buff->W ++;

//printf("inset:%d %d\n",data,p_ring_buff->W);

return (0);

}

/*读取环形队列数据*/

int ring_buff_get(struct ring_buff * p_ring_buff)

{

int data = 0;

if(p_ring_buff == NULL)

{

printf("p null\n");

return (-1);

}

if(get_ring_buff_emptystate(p_ring_buff) == 1)

{

printf("buff is empty\n");

return (-2);

}

//data = p_ring_buff->array[p_ring_buff->R%LEN];

data = p_ring_buff->array[p_ring_buff->R&(LEN -1)];

p_ring_buff->R++;

return data;

}

/*销毁*/

int ring_buff_destory(struct ring_buff * p_ring_buff)

{

if(p_ring_buff == NULL)

{

printf("p null\n");

return (-1);

}

free(p_ring_buff);

return (0);

}

int main()

{

int i = 0;

/*定义一个环形缓冲区*/

ring pt_ring_buff = fifo_init();

/*向环形缓冲区中写入数据*/

for(i = 0;i<10;i++)

{

ring_buff_insert(pt_ring_buff,i);

}

/*从环形缓冲区中读出数据*/

for(i = 0;i<10;i++)

{

printf("%d ",ring_buff_get(pt_ring_buff));

}

/*销毁一个环形缓冲区*/

ring_buff_destory(pt_ring_buff);

return (1);

}

总结

环形队列的使用场景非常多,安卓的音频数据读写,很多都用到环形队列,我们在开发过程中使用的环形队列肯定比我上面的那个例子要复杂的多,我这里演示的是比较简单的功能,但是麻雀虽小,五脏俱全,希望这个麻雀让你们了解这个数据结构。在实际项目中大展身手。

c语言环形队列用法,C语言,环形队列相关推荐

  1. c语言递归的用法,C语言递归操作用法总结

    本文实例总结了C语言递归操作用法.分享给大家供大家参考,具体如下: 用归纳法来理解递归 步进表达式:问题蜕变成子问题的表达式 结束条件:什么时候可以不再是用步进表达式 直接求解表达式:在结束条件下能够 ...

  2. c语言while end用法,c语言eof的用法

    计算机术语,缩写通常为EOF(End Of File),在操作系统中表示资料源无更多的资料可读取.资料源通常称为档案或串流.在C语言中,或更精确地说成C标准函式库中表示文件结束符(end of fil ...

  3. c 语言void函数用法,c语言void的用法

    许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.下面小编就跟大家介绍下c语言void的用法. c语言void的用法1.void的含义 void的字面意思是 ...

  4. 无效的变量名c语言,变量方法用法 _C语言-w3school教程

    C语言 的 变量 变量是内存位置的名称.它用于存储数据.其值可以更改,可以重复使用多次. 它是通过符号表示内存位置的方法,以便可以容易识别. 我们来看一下声明一个变量的语法: type variabl ...

  5. linux中c语言kbhit函数用法,C语言判断用户是否输入-非阻塞函数kbhit

    一.基础研究 要从地址读取数据,肯定是要定义一个指针变量p,用它来实现变换地址和取值的功能.另外程序是当两个条件中的某一个出现时才停止,所以应该用while~do循环语句循环输出n和d,并用while ...

  6. c语言教程+school,C语言教程方法用法 _C语言-w3school教程

    C语言 的 C语言教程 此C语言教程与编程方法面向C语言初学者和专业人士,帮助他们轻松了解和学习C语言编程.我们的C语言教程中使用程序解释每个主题. C语言被开发用于创建系统应用程序,直接与硬件设备( ...

  7. c语言Inqueue函数用法,C语言用两个栈实现队列(完整版)

    队列是一种 先进先出(first in - first out, FIFO)的数据结构,队列中的元素都从后端(rear)入队(push),从前端(front)出队(pop). 实现队列最直观的方法是用 ...

  8. c语言pow函数用法_C语言基础的不能再基础的程序知识!“hello world”!

    涉及到的知识点有:include有两种用法.{}大括号用法解释.C语言自定义名字的要求. c语言库函数printf的解释.编译错误有两种.调用system函数.c语言编译过程. 操作系统结构.指令集中 ...

  9. c语言宏高级用法,C语言宏高级用法 [总结]

    1.前言 今天看代码时候,遇到一些宏,之前没有见过,感觉挺新鲜.如是上网google一下,顺便总结一下,方便以后学习和运用.C语言程序中广泛的使用宏定义,采用关键字define进行定义,宏只是一种简单 ...

最新文章

  1. Entity Framework Core介绍(1)
  2. linux qos 软件,linux下QOS:应用篇 - 博客 - 伯乐在线
  3. Digest authentication
  4. C++ 的变量书写规则探讨
  5. 元宇宙突然大火,可是,到底什么是元宇宙呢?
  6. 嵌入式Linux系统编程学习之十七计时器与信号
  7. [转载]每日构造与冒烟测试
  8. 关于用FOMR提交编码的问题
  9. Bailian2686 打印完数【暴力】
  10. 【高速PCB电路设计】1.高速PCB设计概述
  11. 擎天科技携手阿里云 助力政企客户一键管理碳排放
  12. 你的导师对你说过什么让你至今难以忘怀的话?
  13. 无线路由器介绍和有线路由器上网
  14. 建站影视cms网站源码(含安装说明文档)
  15. 计算机应用基础刘瑞新江国学,天津市高等院校“高职升本科”招生统一考试计算机应用基础考试大纲...
  16. Webpack4.0各个击破(7)plugin篇
  17. 2023二建建筑施工备考第二天Day06水泥
  18. [含lw+源码等]javaweb银行柜员业务绩效考核系统
  19. pep8 python 编码规范下载_PEP8 Python 编码规范整理
  20. JavaScript 美化滑块

热门文章

  1. 页面即时聊天客服功能
  2. SuperMap GIS基础软件地图瓦片问题QA
  3. c#字符串按位转成asc_C# 你也可以写个服务器
  4. java自动换行输出_Java PrintStream.println打印自动换行
  5. 网络营销十技之六:联署计划营销(转载)
  6. Activity 的 isFinishing()、isDestroy()
  7. java arraymap_ArrayMap java.lang.ArrayIndexOutOfBoundsException
  8. PXI8720桥信号数据采集卡-阿尔泰科技
  9. pickle与.pkl文件
  10. C# do-while循环控制台实现简单的猜数字游戏