0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言环形队列的原理和特点

strongerHuang 来源:嵌入式Linux 作者:写代码的篮球球痴 2021-05-11 13:56 次阅读

什么是环形队列?

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

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

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

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

环形队列的特点

1、数组构造环形缓冲区

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

59134ccc-b20d-11eb-bf61-12bb97331649.png

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

5928e3fc-b20d-11eb-bf61-12bb97331649.png

从图片看,我们知道,这个环形缓冲区的读写位置是指向数组的首地址的,环形缓冲区的长度是 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

”);

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

”);

return (-1);

}

if(get_ring_buff_fullstate(p_ring_buff) == 1)

{

printf(“buff is full

”);

return (-2);

}

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

p_ring_buff-》W ++;

//printf(“inset:%d %d

”,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

”);

return (-1);

}

if(get_ring_buff_emptystate(p_ring_buff) == 1)

{

printf(“buff is empty

”);

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

”);

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

}

599cb322-b20d-11eb-bf61-12bb97331649.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

”);

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

”);

return (-1);

}

if(get_ring_buff_fullstate(p_ring_buff) == 1)

{

printf(“buff is full

”);

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

”,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

”);

return (-1);

}

if(get_ring_buff_emptystate(p_ring_buff) == 1)

{

printf(“buff is empty

”);

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

”);

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语言实现环形队列的原理和方法

文章出处:【微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    7033

    浏览量

    89041
  • C语言
    +关注

    关注

    180

    文章

    7604

    浏览量

    136847

原文标题:C语言实现环形队列的原理和方法

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    环形器的特点和应用

    环形器是一个有单向传输特性的三端口器件,它表明器件从1到2,从2到3 和从3到1是导通的,反过来信号从2到1,从3到2和从1到3是隔离的。环形器是有数个端的非可逆器件。
    的头像 发表于 11-29 16:49 400次阅读
    <b class='flag-5'>环形</b>器的<b class='flag-5'>特点</b>和应用

    JavaWeb消息队列使用指南

    在现代的JavaWeb应用中,消息队列(Message Queue)是一种常见的技术,用于异步处理任务、解耦系统组件、提高系统性能和可靠性。 1. 消息队列的基本概念 消息队列是一种应用程序对应
    的头像 发表于 11-25 09:27 149次阅读

    C语言与Java语言的对比

    C语言和Java语言都是当前编程领域中的重要成员,它们各自具有独特的优势和特点,适用于不同的应用场景。以下将从语法特性、内存管理、跨平台性、性能、应用领域等多个方面对
    的头像 发表于 10-29 17:31 342次阅读

    C语言与其他编程语言的比较

    C语言作为一种历史悠久的编程语言,自其诞生以来,一直在软件开发领域扮演着重要角色。它以其高效、灵活和可移植性强的特点,成为了系统级编程的首选语言
    的头像 发表于 10-29 17:30 275次阅读

    嵌入式环形队列与消息队列的实现原理

    嵌入式环形队列,也称为环形缓冲区或循环队列,是一种先进先出(FIFO)的数据结构,用于在固定大小的存储区域中高效地存储和访问数据。其主要特点
    的头像 发表于 09-02 15:29 529次阅读

    玩转RT-Thread之消息队列的应用

    不同来源的数据,确保系统的稳定性和响应速度。一、设计消息结构二、创建消息队列在service.c文件中,我们需要创建一个消息队列来存放这些消息,并在处理线程中接收和
    的头像 发表于 07-23 08:11 616次阅读
    玩转RT-Thread之消息<b class='flag-5'>队列</b>的应用

    按照这样学习C语言,成为卷王不是梦!

    在计算机编程领域,C语言被誉为一种强大而灵活的编程语言,掌握好C语言不仅可以让你轻松驾驭各种编程任务,还能够为你的职业生涯打下坚实的基础。但
    的头像 发表于 07-06 08:04 321次阅读
    按照这样学习<b class='flag-5'>C</b><b class='flag-5'>语言</b>,成为卷王不是梦!

    PLC编程语言C语言的区别

    在工业自动化和计算机编程领域中,PLC(可编程逻辑控制器)编程语言C语言各自扮演着重要的角色。尽管两者都是编程语言,但它们在多个方面存在显著的区别。本文将从多个维度深入探讨PLC编程
    的头像 发表于 06-14 17:11 2832次阅读

    C语言基础-为什么要使用C

    当今最流行的 Linux 操作系统和 RDBMS(Relational Database Management System:关系数据库管理系统) MySQL 都是使用 C 语言编写的。
    发表于 03-25 11:20 443次阅读

    plc编程语言c语言的联系 c语言和PLC有什么区别

    PLC编程语言C语言的联系 PLC(可编程逻辑控制器)是一种针对自动化控制系统的特殊计算机。PLC编程语言是为了控制和管理自动化生产过程中的各种设备而设计的。与之相比,
    的头像 发表于 02-05 14:21 4133次阅读

    c语言,c++,java,python区别

    C语言C++、Java和Python是四种常见的编程语言,各有优点和特点C
    的头像 发表于 02-05 14:11 2394次阅读

    vb语言c++语言的区别

    VB语言C++语言是两种不同的编程语言,虽然它们都属于高级编程语言,但在设计和用途上有很多区别。下面将详细比较VB
    的头像 发表于 02-01 10:20 2322次阅读

    裸机中环形队列与RTOS中消息队列有何区别呢?

    环形队列”和“消息队列”在嵌入式领域有应用非常广泛,相信有经验的嵌入式软件工程师对它们都不陌生。
    的头像 发表于 01-26 09:38 716次阅读
    裸机中<b class='flag-5'>环形</b><b class='flag-5'>队列</b>与RTOS中消息<b class='flag-5'>队列</b>有何区别呢?

    labview 队列最前端插入的应用

    LabVIEW是一种用于实时测试、测量和控制系统的高级系统设计软件。它采用了数据流编程方式,提供了一种直观、可视化的方法来构建复杂的测试和测量应用程序。其中一个重要的功能是队列,它可以在软件设计中
    的头像 发表于 01-08 11:45 1192次阅读

    labview队列有什么实际作用

    LabVIEW队列是一种数据结构,常用于解决多任务并发处理的问题。它被广泛应用于科学研究、工程项目和自动化控制等领域。在LabVIEW中,队列提供了一种高效、方便的方式来处理不同任务之间的数据
    的头像 发表于 01-05 16:42 1596次阅读