深入理解TAILQ队列
来源:互联网 发布:openal是什么软件 编辑:程序博客网 时间:2024/06/05 17:02
宏名称
操作
TAILQ_INIT
初始化队列
TAILQ_FOREACH
对队列进行遍历操作
TAILQ_INSERT_BEFORE
在指定元素之前插入元素
TAILQ_INSERT_TAIL
在队列尾部插入元素
TAILQ_EMPTY
检查队列是否为空
TAILQ_REMOVE
从队列中移除元素
TAILQ_INSERT_AFTER 在指定元素之后插入元素
---------------------------------------------------------------------------------我是分割线------------------------------------------------------------------------------------
1.描述前一个和下一个元素的结构体
458 #define TAILQ_ENTRY(type) \459 struct { \460 struct type *tqe_next; /* next element */ \461 struct type **tqe_prev; /* address of previous next element */ \462 TRACEBUF \463 }这是TAILQ对两个指向前后两个元素指针的抽象,抽象为TAILQ_ENTRY结构体:tqe_next是指向下一个元素的指针,tqe_prev是一个二级指针,指针变量的地址,是前一个元素的tqe_next的地址,解引用(*tqe_prev)之后就是本元素的内存地址;TRACEBUF是一个调试相关的宏,我们先不管它。举例: 我们声明一个结构体,这个结构体只有一个int型整数,还有前驱和后继指针。
struct int_node{int num;TAILQ_ENTRY(int_node);};
2.队列头
TAILQ把整个队列头单独抽象为一个结构体TAILQ_HEAD,如下:
445 /*446 * Tail queue declarations.447 */448 #define TAILQ_HEAD(name, type) \449 struct name { \450 struct type *tqh_first; /* first element */ \451 struct type **tqh_last; /* addr of last next element */ \452 TRACEBUF \453 }这个宏实际上使用的时候,会展开成为一个结构体,tqh_first是一个一级指针,指向队列中的第一个元素;tqh_last是一个二级指针,它指向最后一个元素中的tqe_next(请参考上面的TAILQ_ENTRY),也就是最后一个元素的tqe_next的地址,指针的地址就是二级指针;TRACEBUF是一个用来调试的宏,不用管它。举例: 声明一个叫做queue_head的队列头:
TAILQ_HEAD(my_int_struct, my_int) queue_head;用下面的宏初始化这个队列头:
534 #define TAILQ_INIT(head) do { \535 TAILQ_FIRST((head)) = NULL; \536 (head)->tqh_last = &TAILQ_FIRST((head)); \537 QMD_TRACE_HEAD(head); \538 } while (0)
3.插入元素
插入元素用TAILQ_INSERT_TAIL宏,由于TAILQ中有一个tqh_last的二级指针,所以插入元素直接插到队尾,仅用O(1)时间。
578 #define TAILQ_INSERT_TAIL(head, elm, field) do { \579 QMD_TAILQ_CHECK_TAIL(head, field); \580 TAILQ_NEXT((elm), field) = NULL; \581 (elm)->field.tqe_prev = (head)->tqh_last; \582 *(head)->tqh_last = (elm); \583 (head)->tqh_last = &TAILQ_NEXT((elm), field); \584 QMD_TRACE_HEAD(head); \585 QMD_TRACE_ELEM(&(elm)->field); \586 } while (0)QMD_TAILQ_CHECK_TAIL,QMD_TRACE_HEAD,QMD_TRACE_ELEM这三个宏和调试信息相关和做一些必要的检查,我们可以先不管;这个宏就是在调整相关的指针指向。
4.删除元素
删除元素用TAILQ_REMOVE宏
596 #define TAILQ_REMOVE(head, elm, field) do { \597 QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \598 QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \599 QMD_TAILQ_CHECK_NEXT(elm, field); \600 QMD_TAILQ_CHECK_PREV(elm, field); \601 if ((TAILQ_NEXT((elm), field)) != NULL) \602 TAILQ_NEXT((elm), field)->field.tqe_prev = \603 (elm)->field.tqe_prev; \604 else { \605 (head)->tqh_last = (elm)->field.tqe_prev; \606 QMD_TRACE_HEAD(head); \607 } \608 *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \609 TRASHIT(*oldnext); \610 TRASHIT(*oldprev); \611 QMD_TRACE_ELEM(&(elm)->field); \612 } while (0)QMD_SAVELINK,QMD_TAILQ_CHECK_NEXT,QMD_TAILQ_CHECK_PREV,TRASHIT,同样先不管这几个宏。
5.队列中的第一个元素
512 #define TAILQ_FIRST(head) ((head)->tqh_first)
6.当前元素的下一个元素
591 #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)这个宏比较简单。
7.遍历链表中的每一个元素
用宏TAILQ_FOREACH
514 #define TAILQ_FOREACH(var, head, field) \515 for ((var) = TAILQ_FIRST((head)); \516 (var); \517 (var) = TAILQ_NEXT((var), field))这个宏就比较简单了,用临时变量var来遍历链表中的每一个元素。
------------------------------------------------------------------------------我是分割线 -------------------------------------------------------------
完整实例:
#include <stdio.h>#include <stdlib.h>#include <sys/queue.h>/* 定义一个结构体,它只是尾队列的一个元素 它必须包含一个TAILQ_ENTRY来指向上一个和下一个元素*/struct tailq_entry { int value; TAILQ_ENTRY(tailq_entry) entries;};//定义队列的头部TAILQ_HEAD(, tailq_entry) my_tailq_head;int main(int argc, char *argv[]){ //定义一个结构体指针 struct tailq_entry *item; //定义另外一个指针 struct tailq_entry *tmp_item; //初始化队列 TAILQ_INIT(&my_tailq_head); int i; //在队列里添加10个元素 for(i=0; i<10; i++) { //申请内存空间 item = malloc(sizeof(*item)); if (item == NULL) { perror("malloc failed"); exit(-1); } //设置值 item->value = i; /* 将元素加到队列尾部 参数1:指向队列头的指针 参数2:要添加的元素 参数3:结构体的变量名 */ TAILQ_INSERT_TAIL(&my_tailq_head, item, entries); } //遍历队列 printf("Forward traversal: "); TAILQ_FOREACH(item, &my_tailq_head, entries) { printf("%d ",item->value); } printf("\n"); //添加一个新的元素 printf("Adding new item after 5: "); TAILQ_FOREACH(item, &my_tailq_head, entries) { if (item->value == 5) { struct tailq_entry *new_item = malloc(sizeof(*new_item)); if (new_item == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } new_item->value = 10; //插入一个元素 TAILQ_INSERT_AFTER(&my_tailq_head, item, new_item, entries); break; } } TAILQ_FOREACH(item, &my_tailq_head, entries) { printf("%d ", item->value); } printf("\n"); //删除一个元素 printf("Deleting item with value 3: "); for(item = TAILQ_FIRST(&my_tailq_head); item != NULL; item = tmp_item) { if (item->value == 3) { //删除一个元素 TAILQ_REMOVE(&my_tailq_head, item, entries); //释放不需要的内存单元 free(item); break; } tmp_item = TAILQ_NEXT(item, entries); } TAILQ_FOREACH(item, &my_tailq_head, entries) { printf("%d ", item->value); } printf("\n"); //清空队列 while (item = TAILQ_FIRST(&my_tailq_head)) { TAILQ_REMOVE(&my_tailq_head, item, entries); free(item); } //查看是否为空 if (!TAILQ_EMPTY(&my_tailq_head)) { printf("tail queue is NOT empty!\n"); } return 0; }
0 0
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- 深入理解TAILQ队列
- freeBSD TAILQ队列的理解
- 深入理解FreeBSD中的TAILQ
- 深入理解FreeBSD中的TAILQ
- 深入理解TAILQ队列(转自http://blog.csdn.net/hunanchenxingyu/article/details/8648794)
- 深入理解FreeBSD中的TAILQ ------good
- 关于libevent与FreeBSD内核中TAILQ队列的理解
- queue.h之tailq.h尾队列理解使用
- LINUX下的TAILQ队列
- 深入理解Queue 队列
- 深入理解链式队列
- tailq
- Linux queue.h之TAILQ队列分析!
- JAVA的简单操作注意事项
- Servlet 工作原理解析
- 陈怡暖:数据打压美元,金银逼近关键阻力(午评)
- HttpServletRequest的应用
- javascript中的执行环境和作用域链
- 深入理解TAILQ队列
- 寻找相同元素的指针
- android toast设置比Toast.LENGTH_SHORT还短的持续时间
- AppCan “移动互联网+” 重构传统企业移动化转型
- SpringMVC访问静态资源的三种方式
- Leetcode: House Robber
- FILETIME, SYSTEMTIME 与 time_t 相互转换
- nagios的安装配置
- Linux下动态加载