C语言,环形队列

什么是环形队列?

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

640?wx_fmt=png

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

640?wx_fmt=png

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

640?wx_fmt=png

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

环形队列的特点

1、数组构造环形缓冲区

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

640?wx_fmt=png

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

640?wx_fmt=png

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

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

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

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

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

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

640?wx_fmt=png

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

3个企鹅已经排列

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

640?wx_fmt=png

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

4、再写入3个数据

640?wx_fmt=png

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

5、再写入1个数据

640?wx_fmt=png

这个时候环形队列已经满了,要是想再写入数据的话,就不行了,(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);
}

640?wx_fmt=png

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


/* 实现的最简单的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);
}

总结

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

—————END—————

640?wx_fmt=jpeg
扫码或长按关注
回复「 加群」进入技术群聊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468212.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

音频几个重要的参数

音频的采样率是什么&#xff1f;如果把音频当成一条曲线&#xff0c;那么采样率就是一秒钟从这个曲线里面提取样本的次数。8,000 Hz - 电话所用采样率, 对于人的说话已经足够11,025 Hz - AM调幅广播所用采样率22,050 Hz和24,000 Hz - FM调频广播所用采样率32,000 Hz - miniDV 数…

ps绿化工具_绿化消防车价位

绿化消防车价位绿化消防车价位 4吨东风消防洒水车&#xff0c;又称为多功能消防车&#xff0c;它是在东风原装二类底盘基础上加消防泵、消防炮、洒水炮及洒水车的前冲后洒、侧喷及水罐体组成&#xff0c;既能参加救火灭火功能&#xff0c;水炮的有效射程≥45米&#xff0c;每秒…

今天星期六

突然之间就到周六了&#xff0c;我记得上周的时候&#xff0c;我一个朋友说&#xff0c;这周我们要开个课程&#xff0c;课程的名字就叫做&#xff0c;「如何让你拥有快乐的今天」&#xff0c;然而&#xff0c;上周已经过去&#xff0c;嗖的一声&#xff0c;已经到了这周了&…

C语言验证大小端的几个方法

大小端的问题在很多面试笔试中都会遇到&#xff0c;最直接的考察是&#xff0c;笔试的时候&#xff0c;让你写一个代码&#xff0c;如何确定当前系统是大端还是小端的。什么是大端和小端呢&#xff1f;大端&#xff1a; 高位字节排放在内存的低地址端&#xff0c;低位字节排放在…

Windows系统带你一步一步无脑使用babel

不废话直接写看步骤&#xff1a; 1、在F盘新建一个文件夹叫babel 2、npm init 初始化项目 3、全局安装npm install babel babel-cli -g 4、项目安装npm install babel-cli --save-dev 项目目录里会多一个node_modules包 5、新建一个es6.js文件 随便写一段es6 6、输入指令babel …

python sklearn 归一化_数据分析|Python特征工程(5)

OX00 引言数据和特征决定了机器学习的上限&#xff0c;而模型和算法只是逼近这个上限而已。由此可见&#xff0c;特征工程在机器学习中占有相当重要的地位。在实际应用当中&#xff0c;可以说特征工程是机器学习成功的关键。特征做不好&#xff0c;调参调到老。重视调参&#x…

盘点多款国产Linux桌面操作系统

编辑&#xff1a;strongerHuang微信公众号&#xff1a;strongerHuang素材来源&#xff1a;百度百科、网络国产操作系统多为以Linux 为基础二次开发的操作系统。2014年4月8日起&#xff0c;美国微软公司停止了对Windows XP SP3操作系统提供服务支持&#xff0c;这引起了社会和广…

kafka rabbitmq优劣对比_Kafka、RabbitMQ、RocketMQ等消息中间件的对比

原文链接&#xff1a;Kafka、RabbitMQ、RocketMQ等消息中间件的对比消息中间件现在有不少&#xff0c;网上很多文章都对其做过对比&#xff0c;在这我对其做进一步总结与整理。RocketMQ淘宝内部的交易系统使用了淘宝自主研发的Notify消息中间件&#xff0c;使用Mysql作为消息存…

你应该知道这些有意思的代码

Kyle McCormick 在 StackExchange 上发起了一个叫做 Tweetable Mathematical Art 的比赛&#xff0c;参赛者需要用三条推这么长的代码来生成一张图片。具体地说&#xff0c;参赛者需要用 C 语言编写 RD 、 GR 、 BL 三个函数&#xff0c;每个函数都不能超过 140 个字符。每个函…

python 对xlsx文件数根据日期进行统计分析_Python处理Excel的常用操作(一)

最近一直忙着学习和写开题报告&#xff0c;都没有时间更文了&#xff0c;今天偷偷来休闲一下。很多人一开始学习python&#xff0c;就是看到了很多关于python能够快速处理和解决表格的广告&#xff0c;于是便有了今天的分享。我主要利用pandas库来做一些简单且常规的操作。1、创…

(四)Asp.net web api中的坑-【api的返回值】

void无返回值IHttpActionResultHttpResponseMessage自定义类型我这里并不想赘述这些返回类型&#xff0c; 可以参考博文http://blog.csdn.net/leonken88/article/details/53063693 和大神的http://www.cnblogs.com/landeanfen/p/5501487.html 我要说我遇到的坑是&#xff0c; p…

C语言实现树,你一定看得懂

之前写了好多篇文章关于数据结构的&#xff0c;既然讲到了数据结构&#xff0c;那么就必须要说一下树&#xff0c;树这个数据结构使用范围非常广&#xff0c;应用前景广阔。关联文章&#xff1a;五分钟搞懂什么是红黑树&#xff08;全程图解&#xff09;Linux 内核红黑树分析这…

else应输入一个语句是什么意思_Python基础知识储备,关于if-else使用性能的一点感悟...

前面给大家介绍的if-if分支结构是只要条件满足就会执行&#xff1b;而if-else的语句结构是前面的条件成立执行什么操作&#xff0c;则下面的分支结构就不会被执行&#xff0c;若前面的条件不成立(否则)做什么。以下通过三个案例给大家演示if-else语句的使用方法&#xff1a;Pyt…

你应该拥有的无名剑

想了很久的名字&#xff0c;刹那间我不知道怎么给文章起名字了&#xff0c;一个响亮的名字远比正文来得精彩&#xff0c;既然题目比文章精彩&#xff0c;那么就会喧宾夺主&#xff0c;所以我们看很多古诗词的名字起名《无题》&#xff0c;也可以理解为某个时段&#xff0c;肚子…

你真的知道敏捷和迭代吗?

在这敏捷开发横行的时代中&#xff0c;人人都在谈敏捷&#xff0c;人人都在谈迭代&#xff0c;似乎大家好像都尝到了敏捷带来的甜头&#xff0c;记得有一次跟朋友吃饭&#xff0c;说他们现在的项目用敏捷开发&#xff0c;每个迭代都能看到不断完善的产品&#xff0c;非常有成就…

谈优势成长

以下文章来自我的一个同事&#xff0c;希望他的感悟能够帮助到一些人&#xff0c;大家共勉~工作忙碌的时候总是不能抽中空闲来读书&#xff0c;利用上周坐飞机的2个小时时间&#xff0c;不能看手机&#xff0c;不刷微信&#xff0c;我一口气读了一本好书《优势成长》。这不是一…

@cacheable 设置过期时间_缓存面试三连击——聊聊Redis过期策略?内存淘汰机制?再手写一个LRU 吧!...

大家好&#xff0c;今天我和大家想聊一聊有关redis的过期策略的话题。听到这里你也许会觉得&#xff1a;“我去&#xff0c;我只是个日常搬砖的&#xff0c;这种偏底层的知识点&#xff0c;我需要care吗&#xff1f;”话虽如此&#xff0c;但是兄die,如果你连标题上问题都不知道…

linux终端贪吃蛇,分享|nSnake: 在Linux的终端上玩经典的贪食蛇游戏

你知道20世纪末的那些古老的诺基亚手机上最棒的东西是什么吗&#xff1f; 贪食蛇! 我以前在这个看似无聊但却让人上瘾的游戏上花费了大把的时间。在古老的诺基亚手机被智能手机取代的同时&#xff0c;贪食蛇也被另外的无聊但却令人上瘾的游戏取代了&#xff0c;比如说&#xff…

vue 组件之间数据传递(七)

1、props:父组件 -->传值到子组件 app.vue是父组件 &#xff0c;其它组件是子组件&#xff0c;把父组件值传递给子组件需要使用 >props 在父组件&#xff08;App.vue&#xff09;定义一个属性&#xff08;变量&#xff09;sexVal 男 把该值传递给 子组件(B.vue)&#x…

人在旅途之桂林

先说下这篇文章是多图的所以看文章的同学最好在wifi环境下之前有发文章说我们学院建院十周年所以&#xff0c;哈哈哈&#xff0c;就有机会回桂林嗨皮了出发的时候车子没电了&#xff0c;叫了保险过来搭电搞了一段时间&#xff0c;不过不影响我们顺利到达桂林第一时间先吃碗米粉…