TAIL Queue数据结构
来源:互联网 发布:ubuntu jdk安装 编辑:程序博客网 时间:2024/06/03 15:15
看源代码的时候发现一个新的数据结构,然后我就好好的画了一下这个数据结构的图形,一是为了记录一下我自己的分析过程,二是和大家分享一下这个数据结构。这个数据结构的名字叫TAIL QUEUE感觉很高大上。所以我想分析一下这个数据结构,这个数据结构里面使用到了很多的宏定义。
这个结构体的定义如下:
typedef struct ConfNode_ { char *name; char *val; int is_seq; int allow_override; struct ConfNode_ *parent; TAILQ_HEAD(, ConfNode_) head; TAILQ_ENTRY(ConfNode_) next;} ConfNode;ConfNode结构的图形是这个样子:
TAIL_HEAD又是什么呢?这是一个宏定义,结构如下:
#define TAILQ_HEAD(name, type)\struct name {\struct type *tqh_first;/* first element */\struct type **tqh_last;/* addr of last next element */\}
里面包含了一个两个成员,一个是指向type类型的tqh_first指针,一个是tqh_last,这个是指向指针的指针。这个type就是传过来的ConfNode_,说明这个类型和之前的声明的ConfNode的类型是一样的。里面的注释也写的很清楚,tqh_first指向第一个元素,tqh_last是指向next element的地址。
TAIL_ENTRY这个宏定义如下:
#define TAILQ_ENTRY(type)\struct {\struct type *tqe_next;/* next element */\struct type **tqe_prev;/* address of previous next element */\}同样,这个的解释和上面那个是一样的,没有不同,解释是tqe_next指向的是下一个结点,tqe_prev指向的是上一个元素的地址。
通过替换现在ConfNode结点的代码就如下:
typedef struct ConfNode_ { char *name; char *val; int is_seq; int allow_override; struct ConfNode_ *parent; struct name {struct type *tqh_first;/* first element */struct type **tqh_last;/* addr of last next element */ } head; struct {struct type *tqe_next;/* next element */struct type **tqe_prev;/* address of previous next element */ } next;} ConfNode;现在的结构图变成这个样子了:
接下来就是申明结点的操作:
ConfNode *ConfNodeNew(void){ ConfNode *new; new = SCCalloc(1, sizeof(*new)); if (unlikely(new == NULL)) { return NULL; } /* By default we allow an override. */ new->allow_override = 1; TAILQ_INIT(&new->head); return new;}
这里面主要是TAILQ_INIT这个宏的定义解释:
#defineTAILQ_INIT(head) do {\(head)->tqh_first = NULL;\(head)->tqh_last = &(head)->tqh_first;\} while (0)
这里主要是将刚分配的ConfNode结点元素里面的head变量里的tqh_first和tqh_last进行初始化。
这里的tqh_first初始化为NULL,tqh_last初始化为指向tqh_first,也就是说tqh_last里面出入的是tqh_first的地址。
接下来就是准备插入元素的过程了,插入元素使用的是TAILQ_INSERT_TAIL这个宏定义,在这之前肯定是先声明一个root结点的。
<pre name="code" class="cpp">ConfNode *parent = NULL;
ConfNode *node = parent;刚开始插入的时候,由于这两个结点都是NULL,还没有分配任何空间,所以肯定是不行的,在里面有地方是给它分配空间的,这个代码就是这里:
node = ConfNodeNew();因为node和parent指向的是同一个地方,所以开始插入的时候比较特殊。
TAILQ_INSERT_TAIL(&parent->head, node, next);
TAILQ_INSERT_TAIL宏定义的实现如下:
#define TAILQ_INSERT_TAIL(head, elm, field) do {\(elm)->field.tqe_next = NULL;\(elm)->field.tqe_prev = (head)->tqh_last;\*(head)->tqh_last = (elm);\(head)->tqh_last = &(elm)->field.tqe_next;\} while (0)呀呀呀,这个东西看上去有点绕了,那我就用画图的形式来解释吧。其实它做的工作也就那么点并没有很复杂。刚开始分配空间的时候tqh_first和tqh_last是初始化过的,还记得吧,tqh_last指向tqh_first。
第一步刚开始初始化的情况如下:
接下来执行第一步:
(elm)->field.tqe_next = NULL;
接下来就是指向下面的代码:
(elm)->field.tqe_prev = (head)->tqh_last;第一次插入的时候注意的是elm和head其实是同一个结点,所以都是对这个结点进行操作,这个执行的意思是tqe_prev和tqh_last是指向同一个地方的,tqh_last我们知道,指向的是tqh_first。所以tqe_prev也是指向tqh_first。
接下来的两行代码执行的其实就是修改了里面的指针:
*(head)->tqh_last = (elm);(head)->tqh_last = &(elm)->field.tqe_next;第一行代码我们知道tqh_last指向的是tqh_first的地址,所以操作*(head)->tqh_last其实就是操作的tqh_first。而这个tqh_first = NULL,所以第一行代码就是修改tqh_first的值,使得tqh_first指向这个结构体的开始。
最后一步就是修改tqh_last的值了,使这个值指向之后一个结点,但这个时候里面的结点只有一个,所以tqh_last指向的是tqe_next的地址。
最后我将画一下多个结点的情况,这个也就是在里面修改一下指针而已。图示如下:
如果看不清楚请原谅,我已经很注意了。如果有什么问题请大家提出来,希望大家讲讲这个数据机构的优点,我是有点没有想明白,双向循环链表也是可以实现的啊。
0 0
- TAIL Queue数据结构
- Tail queue definitions
- tail queue的理解
- libevent中的tail queue详细分析
- libevent 学习----------尾队列 tail queue
- tail queue in queue.h for free bsd.
- 队列数据结构 Queue.h
- 【数据结构】顺序队列 Queue
- queue的实现 数据结构
- <数据结构>stack & queue
- Java 数据结构之Queue
- 数据结构-队列(queue)
- linkin大话数据结构--Queue
- 数据结构-Queue
- 数据结构_队列(queue)
- 数据结构-队列(queue)
- 数据结构复习 - 队列Queue
- 计蒜客 数据结构 Queue
- Solr的部署
- spring MVC 文件执行顺序
- 稀疏表示综述:A Survey of Sparse Representation: Algorithms and Applications_2015(1)
- hdu 4084
- HashMap与HashTable的区别
- TAIL Queue数据结构
- hihoCoder 1014 Trie树 (Trie)
- ConcurrentModificationException异常总结-多线程方式
- Maven提高篇系列之——使用Profile
- Struts2之数据标签(一)
- Motion Segmentation by Velocity Clustering with Estimationof Subspace Dimension阅读报告
- leetcode系列(15)移除链表中的指定元素
- EFM8单片机与I2C外设通信
- 配置文件读取properties(一)