顺序循环队列
环形队列是在实际编程极为有用的数据结构,它有如下特点。
   它是一个首尾相连的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
三,设置一个计数器count
     队列空:count==0;
     队列满:count>0&&tail==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.   第一种设计方法: 
  20.      当head == tail 时,tag = 0 为空,等于 = 1 为满。 
  21. */  
  22.   
  23. extern int ringq_init(RINGQ * p_queue);  
  24.   
  25. extern int ringq_free(RINGQ * p_queue);  
  26.   
  27.   
  28. /* 加入数据到队列 */  
  29. extern int ringq_push(RINGQ * p_queue,int data);  
  30.   
  31. /* 从队列取数据 */  
  32. extern int ringq_poll(RINGQ * p_queue,int *p_data);  
  33.   
  34.   
  35. #define ringq_is_empty(q) ( (q->head == q->tail) && (q->tag == 0))  
  36.   
  37. #define ringq_is_full(q) ( (q->head == q->tail) && (q->tag == 1))  
  38.   
  39. #define print_ringq(q) printf("ring head %d,tail %d,tag %d\n", q->head,q->tail,q->tag);  
  40. #ifdef __cplusplus  
  41. }  
  42. #endif   
  43.   
  44. #endif /* __RINGQ_H__ */  

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

 
 
三.预留空间环境队列
 
 -------------------------------------------------------------------
 
不采用tag,只留一个空间
  读书笔记之顺序循环队列_循环队列_02
 
初始化状态: 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.   取消tag .限制读与写之间至少要留一个空间 
  19.   队列空 head == tail . 
  20.   队列满是 (tail+1)%MAX == head   
  21.   初始化是head = tail = 0;    
  22. */  
  23.   
  24. extern int ringq_init(RINGQ * p_ringq);  
  25.   
  26. extern int ringq_free(RINGQ * p_ringq);  
  27.   
  28. extern int ringq_push(RINGQ * p_ringq,int data);  
  29.   
  30. extern int ringq_poll(RINGQ * p_ringq,int * p_data);  
  31.   
  32. #define ringq_is_empty(q) (q->head == q->tail)  
  33.   
  34. #define ringq_is_full(q) (((q->tail+1)%q->size) == q->head )  
  35.   
  36. #define print_ringq2(q,d) printf("ring head %d,tail %d,data %d\n", q->head,q->tail,d);  
  37.   
  38. #ifdef __cplusplus  
  39. }  
  40. #endif   
  41.   
  42. #endif /* __QUEUE_H__ */  
 

实现代码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;