TAIL Queue数据结构

看源代码的时候发现一个新的数据结构,然后我就好好的画了一下这个数据结构的图形,一是为了记录一下我自己的分析过程,二是和大家分享一下这个数据结构。这个数据结构的名字叫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这个宏的定义解释:

#define	TAILQ_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的地址。

最后我将画一下多个结点的情况,这个也就是在里面修改一下指针而已。图示如下:

如果看不清楚请原谅,我已经很注意了。如果有什么问题请大家提出来,希望大家讲讲这个数据机构的优点,我是有点没有想明白,双向循环链表也是可以实现的啊。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-09-17 09:39:30

TAIL Queue数据结构的相关文章

POJ 2259 Team Queue 数据结构 队列

Team Queue Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3282   Accepted: 1188 Description Queues and Priority Queues are data structures which are known to most computer scientists. The Team Queue, however, is not so well known, thoug

POJ 3125 Printer Queue 数据结构 队列

Printer Queue Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4329   Accepted: 2269 Description The only printer in the computer science students' union is experiencing an extremely heavy workload. Sometimes there are a hundred jobs in t

第二十四篇 玩转数据结构——队列(Queue)

1.. 队列基础 队列也是一种线性结构: 相比数组,队列所对应的操作数是队列的子集: 队列只允许从一端(队尾)添加元素,从另一端(队首)取出元素: 队列的形象化描述如下图: 队列是一种先进先出(First In First Out)的数据结构: 2.. 队列的实现 任务目标如下: Queue<E> ·void enqueue(E) //入队 ·E dequeue() //出队 ·E getFront() //查看队首元素 ·int getSize() //查看队列中元素的个数 ·boolean

queue

queue是一种先进先出的数据结构.以下由简入繁引入queue. queue的操作主要有:入队,出队,空满判断等. 1. 数组实现简单队列 #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #define MAX 10 int arr[MAX]; int head = 0; int tail = 0; int counter = 0; void enqueue(int value) { arr[tai

数据结构专题——队列

一.队列(queue)(可与栈对比进行学习) 思想:队列实现的是一种先进先出(first-in,first-out,FIFO)策略.(<算法导论>) 定义:队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表(具有线性关系/前驱后继关系).(<大话数据结构>) 术语: 队列的两端:队头(head):进行删除操作的一端.队尾(tail):进行插入操作的一端. 操作:队列的插入操作(insert):入队(enqueue). 队列的删除操作(delete):出队(dequeue

《数据结构与算法分析》学习笔记(五)&mdash;&mdash;队ADT

一.队的概念        队列也是一种表,但是是一种受限的表,只允许从一端插入,另一端山粗的表. 二.队列的数组实现 #define QMAXSIZE 100 typedef int Position; typedef int QElement; typedef struct queue { QElement Els[QMAXSIZE]; Position head,tail; }Queue; void QCreate(Queue &Q) { Q.head = Q.tail = 0; } vo

3.数据结构--队列

队列是一种先进先出的线性数据结构 1.队列的实现 public interface Queue<E> { int getSize(); boolean isEmpty(); void enqueue(E e); E dequeue(); E getFront(); } 实现队列 public class ArrayQueue<E> implements Queue<E>{ private Array<E> array; public ArrayQueue(i

纯数据结构Java实现(2/11)(栈与队列)

栈和队列的应用非常多,但其起实现嘛,其实很少人关心. 虽然苹果一直宣传什么最小年龄的编程者,它试图把编程大众化,弱智化,但真正的复杂问题,需要抽丝剥茧的时候,还是要 PRO 人士出场,所以知根知底,实在是必要之举(而非无奈之举). 大门敞开,越往里走越窄,竞争会越激烈. 栈 基本特性 就一条,FILO.但是用在其他复杂数据结构,比如树,或者用在其他应用场景的时候,比如记录调用过程中的变量及其状态等,超有用. 应用举例 比如 撤销操作: 用户每次的录入都会入栈,被系统记录,然后写入文件:但是用户撤

数据结构总结(UPDATING......)

目标: 1.栈........√ 2.队列......√ 3.堆.........× 4.并查集...× 栈: 1 #define MAXN 65536 2 struct stack{ 3 int sz[MAXN],now; 4 stack() 5 { 6 now=0; 7 } 8 ~stack() 9 { 10 delete []sz; 11 } 12 void push(int x) 13 { 14 if(!full()) 15 sz[++now]=x; 16 } 17 int pop()