循环队列
来源:互联网 发布:乐高ev3编程视频教程 编辑:程序博客网 时间:2024/05/17 07:42
1、引
- 对于嵌入式编程,经常要用的的外围接口就是串口了,在串口中断中,一般只会收发,而不会做其它的事,收发的数据一般都来自一个队列里。
2、定义
队列一般定义为先进先出的容器,入队时把数据插入到队尾,出队时将数据从队头取出——-FIFO.。
一般队列都有以下的属性和方法:
- front
back
empty
- size
- push_back
- pop_front
3、C语言实现
结构体
#define SIZE 1024 struct Queue{ int front,back; //头、尾指针 unsigned char data[SIZE]; // 缓冲区大小 bool (*empty)(Queue*); //判空 int (*size)(Queue*); //剩余大小 bool (*push_back)(Queue*,unsigned char); // 入队 bool (*pop_front)(Queue*,unsigned char*);// 出队};
模块内部的接口定义
static bool empty(Queue* q);static int size(Queue*q);static bool push_back(Queue* q,unsigned char d);static bool pop_front(Queue* q,unsigned char* d);
//对外的初始化接口
void init(Queue* q){ q->back = 0 ; q->front = 0; q->size = &size; q->empty = ∅ q->pop_front = &pop_front; q->push_back = &push_back;}
//方法的实现
static bool empty(Queue* q){ return q->back == q->front;}static int size(Queue*q){ return (q->back - q->front + SIZE)%SIZE;}static bool push_back(Queue* q,unsigned char d){ if((q->back+1)%SIZE == q->front) { return false; } else { q->data[q->back] = d; q->back = (q->back+1)%SIZE; return true; }}static bool pop_front(Queue* q,unsigned char* d){ if(q->empty(q)) { return false; } else { *d = q->data[q->front]; q->front = (q->front+1)%SIZE; return true; }}
使用:
Queue queue; init(&queue); //入队 for(int i = 0 ; i < 10;i++) queue.push_back(&queue,i); //出队 unsigned char d; bool ret = queue.pop_front(&queue,&d) ;
4、节省空间
这里我们定义了一个长度为SIZE的缓冲区,入队时的判断是如下:
if((q->back+1)%SIZE == q->front)//判满 { return false; }
如果定义了SIZE个大小的空间,我们只能使用SIZE-1个空间的大小,使用一个空间来判满。
这对于空间比较充裕的系统来说没有毛病,如果数组的元素是结构体,而且这个结构体还很大时,这就显得相当的浪费了,比如在接收CAN数据帧时LINUX内核里定义了如下结构体:
*/struct can_frame { canid_t can_id;/* 32 bit CAN_ID + EFF/RTR/ERR flags */ __u8 can_dlc; /* data length code: 0 .. 8 */ __u8 data[8] __attribute__((aligned(8)));};
这个结构体是8字节对齐的。
这里为了节省空间可以加多一个标志位:
这个标志位的作用如何运作呢?
初始为:0
如果 (q->back == q->front) && (q->flag == 0); 则是空
如果 (q->back == q->front) && (q->flag == 1); 则是满
入队时:q->back == q->front 刚满了。
出队时:q->back == q->front 刚空了。
需要注意是:满后第一次出队,空时的最后一次出队
5、 Version 2
#define SIZE 5#define VER2struct Queue{ int front,back;#ifdef VER2 int flag; //新加的标志#endif unsigned char data[SIZE]; bool (*empty)(Queue*); bool (*full)(Queue*); int (*size)(Queue*); bool (*push_back)(Queue*,unsigned char); bool (*pop_front)(Queue*,unsigned char*);};
初始化:
void init(Queue* q){#ifdef VER2 q->back = 0 ; q->front = 0; q->flag = 0; //初始化为0#else q->back = 0 ; q->front = 0;#endif q->size = &size; q->empty = ∅ q->full = &full; q->pop_front = &pop_front; q->push_back = &push_back;}
空与满的判断:
static bool empty(Queue* q){#ifdef VER2 return (q->back == q->front) && (q->flag == 0);//here#else return q->back == q->front;#endif}static bool full(Queue* q){#ifdef VER2 return (q->back == q->front) && (q->flag == 1);//here#else return (q->back+1)%SIZE == q->front#endif}
入队与出队操作:
static bool push_back(Queue* q,unsigned char d){#ifdef VER2 if(q->full(q)) return false; else { q->data[q->back] = d; q->back = (q->back+1)%SIZE; if(q->back == q->front && q->flag == 0)//入队时,头尾相接则满了 { q->flag = 1; } return true; }#else if(q->full(q)) { return false; } else { q->data[q->back] = d; q->back = (q->back+1)%SIZE; return true; }#endif}static bool pop_front(Queue* q,unsigned char* d){#ifdef VER2 if(q->empty(q)) { return false; } else { int tmp = q->front; //这里存一个临时变量 *d = q->data[q->front]; q->front = (q->front+1)%SIZE; //出最后一个数据的时候要注意,不然头指针会跑到尾指针后面去了。 //也要保证满了后的第一次出队正常 if(tmp == q->back && q->flag == 0) q->front = q->back; q->flag = 0; return true; }#else if(q->empty(q)) { return false; } else { *d = q->data[q->front]; q->front = (q->front+1)%SIZE; return true; }#endif}
6、总结
- 简单,基础
- 尾指针指向下一个空的位置
7、参考资料
https://en.wikipedia.org/wiki/Queue
https://www.tutorialspoint.com/data_structures_algorithms/dsa_queue.htm
阅读全文
0 0
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- 循环队列
- Drying (二分法)
- python网络爬虫与信息采取之解析网页(二)---BeautifulSoup库的find()和find_all()
- 递归简论
- JAVA深入研究——Method的Invoke方法。
- poj 2065 SETI(高斯消元)
- 循环队列
- 聚类方法之k-mean算法
- hpuoj【1410】QAQ & 火星情报局【数学】
- Django编写中间件实现url自定义过滤
- 面向对象思想-封装拖拽对象
- PHP与Shell交互
- 前端入门方法
- curl详细用法
- 《numpy学习指南》学习笔记——常用函数