【转】环形队列理论

原文链接:http://blog.sina.com.cn/s/blog_8b200d440100xsug.html

环形队列是在实际编程极为有用的数据结构,它有如下特点。

它是一个首尾相连的FIFO的数据结构,采用数组的线性空间,数据组织简单。能很快知道队列是否满为空。能以很快速度的来存取数据。

因为有简单高效的原因,甚至在硬件都实现了环形队列.

环形队列广泛用于网络数据收发,和不同程序间数据交换(比如内核与应用程序大量交换数据,从硬件接收大量数据)均使用了环形队列.

一.环形队列实现原理

------------------------------------------------------------

内存上没有环形的结构,因此环形队列实上是数组的线性空间来实现。那当数据到了尾部如何处理呢?它将转回到0位置来处理。这个的转回是通过取模操作来执行的。

因此环列队列的是逻辑上将数组元素q[0]与q[MAXN-1]连接,形成一个存放队列的环形空间。

为了方便读写,还要用数组下标来指明队列的读写位置。head/tail.其中head指向可以读的位置,tail指向可以写的位置。

环形队列的关键是判断队列为空,还是为满。当tail追上head时,队列为满时,当head追上tail时,队列为空。但如何知道谁追上谁。还需要一些辅助的手段来判断.

如何判断环形队列为空,为满有两种判断方法。

一.是附加一个标志位tag

当head赶上tail,队列空,则令tag=0,
      当tail赶上head,队列满,则令tag=1,

二.限制tail赶上head,即队尾结点与队首结点之间至少留有一个元素的空间。

      队列空:   head==tail
      队列满:   (tail+1)% MAXN ==head

二.附加标志实现算法

-------------------------------------------------------------

采用第一个环形队列有如下结构

1 typedef struct ringq{
2    int head;
3    int tail;
4    int tag ;
5    int size ;
6    int space[RINGQ_MAX];
7
8 }RINGQ;  

初始化状态: q->head = q->tail = q->tag = 0;

队列为空:(q->head == q->tail) && (q->tag == 0)

队列为满: ((q->head == q->tail) && (q->tag == 1))

入队操作:如队列不满,则写入

     q->tail =  (q->tail + 1) % q->size ;
出队操作:如果队列不空,则从head处读出。

下一个可读的位置在 q->head =  (q->head + 1) % q->size

完整代码

头文件ringq.h

 1 #ifndef __RINGQ_H__
 2 #define __RINGQ_H__
 3
 4 #ifdef __cplusplus
 5 extern "C" {
 6 #endif
 7
 8 #define QUEUE_MAX 20
 9
10 typedef struct ringq{
11    int head;
12    int tail;
13    int tag ;
14     int size ;
15    int space[QUEUE_MAX];
16 }RINGQ;
17
18
19 extern int ringq_init(RINGQ * p_queue);
20
21 extern int ringq_free(RINGQ * p_queue);
22
23 extern int ringq_push(RINGQ * p_queue,int data);
24
25 extern int ringq_poll(RINGQ * p_queue,int *p_data);
26
27 #define ringq_is_empty(q) ( (q->head == q->tail) && (q->tag == 0))
28
29 #define ringq_is_full(q) ( (q->head == q->tail) && (q->tag == 1))
30
31 #define print_ringq(q) printf("ring head %d,tail %d,tag %d\n", q->head,q->tail,q->tag);
32 #ifdef __cplusplus
33 }
34 #endif
35
36 #endif   

实现代码 ringq.c

 1 #include <stdio.h>
 2 #include "ringq.h"
 3
 4 int ringq_init(RINGQ * p_queue)
 5 {
 6    p_queue->size = QUEUE_MAX ;
 7
 8    p_queue->head = 0;
 9    p_queue->tail = 0;
10
11    p_queue->tag = 0;
12
13    return 0;
14 }
15
16 int ringq_free(RINGQ * p_queue)
17 {
18   return 0;
19 }
20
21
22 int ringq_push(RINGQ * p_queue,int data)
23 {
24   print_ringq(p_queue);
25
26   if(ringq_is_full(p_queue))
27    {
28
29      printf("ringq is full\n");
30      return -1;
31    }
32
33    p_queue->space[p_queue->tail] = data;
34
35    p_queue->tail = (p_queue->tail + 1) % p_queue->size ;
36
37
38    if(p_queue->tail == p_queue->head)
39     {
40        p_queue->tag = 1;
41     }
42
43     return p_queue->tag ;
44 }
45
46 int ringq_poll(RINGQ * p_queue,int * p_data)
47 {
48    print_ringq(p_queue);
49   if(ringq_is_empty(p_queue))
50    {
51
52       printf("ringq is empty\n");
53      return -1;
54    }
55
56    *p_data = p_queue->space[p_queue->head];
57
58    p_queue->head = (p_queue->head + 1) % p_queue->size ;
59
60
61    if(p_queue->tail == p_queue->head)
62     {
63        p_queue->tag = 0;
64     }
65     return p_queue->tag ;
66 }  

测试代码

 1 void test5()
 2 {
 3   RINGQ rq, * p_queue;
 4   int i,data;
 5
 6   p_queue = &rq;
 7
 8   ringq_init(p_queue);
 9
10   for(i=0; i < QUEUE_MAX +2 ; i++)
11   {
12
13    ringq_push(p_queue,i+1);
14   }
15
16   if(ringq_poll(p_queue,&data)>=0)
17      PRINT_INT(data);
18
19   if(ringq_poll(p_queue,&data)>=0)
20      PRINT_INT(data);
21
22   if(ringq_poll(p_queue,&data)>=0)
23      PRINT_INT(data);
24
25   if(ringq_poll(p_queue,&data)>=0)
26      PRINT_INT(data);
27
28   if(ringq_poll(p_queue,&data)>=0)
29      PRINT_INT(data);
30
31   if(ringq_poll(p_queue,&data)>=0)
32      PRINT_INT(data);
33
34   ringq_free(p_queue);
35 }
36
37
38 void test6()
39 {
40   RINGQ rq, * p_queue;
41   int i,data;
42
43   p_queue = &rq;
44
45   ringq_init(p_queue);
46
47
48    ringq_push(p_queue,1);
49
50    ringq_push(p_queue,2);
51
52
53   if(ringq_poll(p_queue,&data)>=0)
54      PRINT_INT(data);
55
56   if(ringq_poll(p_queue,&data)>=0)
57      PRINT_INT(data);
58
59   if(ringq_poll(p_queue,&data)>=0)
60      PRINT_INT(data);
61
62   if(ringq_poll(p_queue,&data)>=0)
63      PRINT_INT(data);
64
65   ringq_push(p_queue,3);
66
67   ringq_push(p_queue,4);
68
69   ringq_push(p_queue,5);
70
71   if(ringq_poll(p_queue,&data)>=0)
72      PRINT_INT(data);
73
74   if(ringq_poll(p_queue,&data)>=0)
75      PRINT_INT(data);
76
77    ringq_push(p_queue,6);
78
79    if(ringq_poll(p_queue,&data)>=0)
80      PRINT_INT(data);
81
82      if(ringq_poll(p_queue,&data)>=0)
83      PRINT_INT(data);
84
85   ringq_free(p_queue);
86 }  

三.预留空间环境队列

-------------------------------------------------------------------

不采用tag,只留一个空间

初始化状态: q->head = q->tail = q->tag = 0;

队列为空:(q->head == q->tail)

队列为满: (((q->tail+1)%q->size) == q->head )

入队操作:如队列不满,则写入

     q->tail =  (q->tail + 1) % q->size ;
出队操作:如果队列不空,则从head处读出。

下一个可读的位置在 q->head =  (q->head + 1) % q->size

头文件

ringq.h

 1 #ifndef __RINGQ_H__
 2 #define __RINGQ_H__
 3
 4 #ifdef __cplusplus
 5 extern "C" {
 6 #endif
 7
 8 #define RINGQ_MAX 20
 9
10 typedef struct ringq{
11    int head;
12    int tail;
13    int size ;
14    int space[RINGQ_MAX];
15 }RINGQ;
16
17
18
19 extern int ringq_init(RINGQ * p_ringq);
20
21 extern int ringq_free(RINGQ * p_ringq);
22
23 extern int ringq_push(RINGQ * p_ringq,int data);
24
25 extern int ringq_poll(RINGQ * p_ringq,int * p_data);
26
27 #define ringq_is_empty(q) (q->head == q->tail)
28
29 #define ringq_is_full(q) (((q->tail+1)%q->size) == q->head )
30
31 #define print_ringq2(q,d) printf("ring head %d,tail %d,data %d\n", q->head,q->tail,d);
32
33 #ifdef __cplusplus
34 }
35 #endif
36
37 #endif   

实现代码ringq.c

 1 #include <stdio.h>
 2
 3 #include "ringq.h"
 4
 5 int ringq_init(RINGQ * p_ringq)
 6 {
 7   p_ringq->size = RINGQ_MAX;
 8
 9   p_ringq->head = 0;
10   p_ringq->tail = 0;
11
12   return p_ringq->size;
13 }
14
15 int ringq_free(RINGQ * p_ringq)
16 {
17   return 0;
18 }
19
20
21 int ringq_push(RINGQ * p_ringq,int data)
22 {
23    print_ringq(p_ringq,data);
24
25    if(ringq_is_full(p_ringq))
26      {
27          printf("ringq is full,data %d\n",data);
28            return -1;
29      }
30
31    p_ringq->space[p_ringq->tail] = data;
32
33    p_ringq->tail = (p_ringq->tail + 1) % p_ringq->size ;
34
35     return p_ringq->tail ;
36 }
37
38
39 int ringq_poll(RINGQ * p_ringq,int * p_data)
40 {
41    print_ringq(p_ringq,-1);
42   if(ringq_is_empty(p_ringq))
43    {
44      printf("ringq is empty\n");
45      return -1;
46    }
47
48    *p_data = p_ringq->space[p_ringq->head];
49
50    p_ringq->head = (p_ringq->head + 1) % p_ringq->size ;
51
52    return p_ringq->head;
53 } 
时间: 2024-07-30 06:23:36

【转】环形队列理论的相关文章

一种用于直播缓冲的环形队列设想

随着各种盒子的涌现,高清的P2P直播研究开始有些返潮:在技术上,P2P直播分为几大块,一是资源获取,二是资源的缓冲设计,三是用户间的分发.交互处理,四是播放和呈现其中,二三比较关键,设计的好坏决定了最终效果:出于对P2P研究的爱好,一直关注这一块的优化设计,参考的文献也较多(此处省略各种大牛文献列表):网上充斥着各种环形队列的设计理论,个人感觉写得太高大上了,不是从一个码农真正理解的角度去写参考tvants的缓冲设计,提出一个类似的环形队列状态 : #已生产  *未生产 ------------

队列理论和队列网络模型 queueing theory and queueing network model

(学了大半个月,赶紧把脑袋里装的东西倒一点点出来,不然就忘记了.看别人的PPT都是顺理成章.一气呵成,看我能讲出多少东西) 1队列理论 队列在生活中随处可见,例如排队买票,排队打饭,排队做地铁等等.那将诸如此类的队列抽象一下,可归纳为一下3要术:排队能容纳的总人数(例如食堂空间只有那么大,最长的队伍只能容纳20人).服务率(例如食堂阿姨打菜的速度).等待时间.   我们通过数学公式以及生活常识可得到如下关系:排队总人数=服务率乘以等待时间. 将队列理论应用于服务器处理的排队,那么排队的要素增加一

Atitit.提升软件稳定性---基于数据库实现的持久化 循环队列 环形队列

Atitit.提升软件稳定性---基于数据库实现的持久化  循环队列 环形队列 1. 前言::选型(马) 1 2. 实现java.util.queue接口 1 3. 当前指针的2个实现方式 1 1.1. 用一个游标last 来指示 (指针表字段last ),麻烦的,不推荐 1 1.2. (简单,推荐)使用循环次数来指示,每循环加1   (字段cirTimes),order by cirtimes 1 4. 表格设计id, cirTimes,createtime,handlerID,recID,d

环形缓冲区的设计及其在生产者消费者模式下的使用(并发有锁环形队列)

1.环形缓冲区 缓冲区的好处,就是空间换时间和协调快慢线程.缓冲区可以用很多设计法,这里说一下环形缓冲区的几种设计方案,可以看成是几种环形缓冲区的模式.设计环形缓冲区涉及到几个点,一是超出缓冲区大小的的索引如何处理,二是如何表示缓冲区满和缓冲区空,三是如何入队.出队,四是缓冲区中数据长度如何计算. ps.规定以下所有方案,在缓冲区满时不可再写入数据,缓冲区空时不能读数据 1.1.常规数组环形缓冲区 设缓冲区大小为N,队头out,队尾in,out.in均是下标表示: 初始时,in=out=0 队头

并发无锁之环形队列生产者消费者问题

1.生产者消费者问题 三种关系:生产者--生产者(互斥):消费者-消费者(互斥):生产者--消费者(互斥同步) 两个角色:生产者:消费者 一种生产场所:缓冲区 2.环形队列(缓冲区) 数据结构:可以有多种,这里选用数组,逻辑上将a[0]和a[size-1]相连构成环形队列 判断空/判断满:当读指针和写指针指向同一个区域为空,或者满(但不能区分空或者满) 两种方案:1.即尾结点与首结点之间至少留有一个元素的空间. 2. 添加一个计数器(信号量就是计数器所以这里用信号量完成计数器的功能) 3.sem

环形队列的实现原理

环形队列是一个首尾相连的FIFO(命名管道)的数据结构,它采用数组的线性空间.它能很快知道队列是否为满或者为空,也能很快的存取数据. 原理: 内存上没有环形结构,因此环形队列利用数组的线性空间来实现.当数据到了尾部时,它将转回到0位置来处理.这个转回操作通过取模来执行. 构造:逻辑上,将数组q[0]与q[MAXN-1]相连接,形成一个存放队列的环形空间. 用数组下标来标明队列的读.写位置.head 指向可以读的位置,tail 指向可以写的位置. 环形队列的关键是判断队列为空或者满.tail 追上

java实现数据结构中的环形队列

最近在看数据结构,队列在数据结构中是个重要的元素. 定义:数据结构是指相互之间存在一种或多种特定关系的数据元素的集合. 队列主要分为普通队列和环形队列,环形队列比普通队列的使用效率更高(普通队列容易造成内存的浪费,时间效率也会降低,主要体现在队列的删除操作上) 下面用java来实现队列,仅供参考 package demo; //环形队列 public class QueueDemo { //创建队列 public QueueDemo(int num){ m_iQueueCapacity=num;

&lt;2014 05 16&gt; 线性表、栈与队列——一个环形队列的C语言实现

栈与队列都是具有特殊存取方式的线性表,栈属于先进后出(FILO),而队列则是先进先出(FIFO).栈能够将递归问题转化为非递归问题,这是它的一个重要特性.除了FILO.FIFO这样的最普遍存取方式外,还有一些扩展的数据结构,如双端队列.双栈.超队列.超栈等,它们是一种扩展与变异结构. 线性表有顺序存储和链接存储两类,这是针对计算机的线性存储空间作出的分类.前者可以是数组,后者可以是链表.字符串是线性表最常见的应用. 这里我用C语言实现了一个基于数组环形队列,它具有固定的队列空间.相比于链表实现,

顺序对列,环形队列,反向链式栈

1.顺序队列 #include<stdio.h> #include <stdlib.h> #define N 100 #define datatype int typedef struct queue { datatype data[N]; int rear;//吃东西 int front;//拉屎 } myQ ,*PmyQ; void init(PmyQ p); int isfull(PmyQ p); int isempty(PmyQ p); void show(PmyQ p);