深入理解TAILQ队列

604 篇文章 8 订阅
579 篇文章 5 订阅

宏名称

操作

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;
    
}















  • 3
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值