sys/queue.h

Linux 内嵌链表(sys/queue.h)详解

  • queue 简介
  • SLIST( 单链表 )
  • STAILQ(单向有尾链表)
  • LIST (双向链表 )
  • SIMPLEQ (简单队列)
  • TAILQ( 尾队列 )
  • CIRCLEQ (循环队列)
  • 例程

queue 简介

C语言不像C++语言可以使用STL,在编程中需要用到链表时,通常需要程序员重新设计链表的结构体。不统一的编程规范会增加代码的阅读难度,而且链表的正确性需要验证。

头文件queue.h为C语言中的链表提供了更加标准规范的编程接口。如今的版本多为伯克利加州大学1994年8月的8.5版本。

queue.h 在 Linux 系统中的路径是 /usr/include/x86_64-linux-gnu/sys/queue.h 。更多资料可以查阅 manual 手册的queue(3)

queue 分为 SLIST、LIST、STAILQ、TAILQ、CIRCLEQ ,不同的链表有着不同的功能支持。queue 的所有源码都是宏定义,因此完全包含于queue.h当中,无需编译为库文件。

每种结构都支持基本的操作:

  1. 在链表头插入节点
  2. 在任意的节点后插入节点
  3. 移除链表头后的节点
  4. 前向迭代遍历链表
功能支持 SLIST LIST STAILQ TAILQ CIRCLEQ
EMPTY + + + + +
FIRST + + + + +
NEXT + + + + +
PREV + +
LAST + +
FOREACH + + + + +
FOREACH_REVERSE + +
INSERT_HEAD + + + + +
INSERT_BEFORE + + +
INSERT_AFTER + + + + +
INSERT_TAIL + + +
CONCAT + +
REMOVE_HEAD + +
REMOVE + + + + +
LOOP_NEXT +
LOOP_PREV +

SLIST

SLIST 是Singly-linked List 的缩写,意为单向无尾链表。

sys/queue.h

SLIST 是最简单的结构,它适合数据量非常大而几乎不需要删除数据的场合,又或者当做堆栈使用。

/*
 * Singly-linked List definitions.
 * 定义表头结点。 
 * name: 表头结点名。 
 * type: 结点类型。
 */
#define SLIST_HEAD(name, type)                                              \
struct name {                                                               \
    struct type *slh_first; /* first element */                             \
}

/*
 * 初始化头结点。 
 * head: 表头结点。
*/
#define SLIST_HEAD_INITIALIZER(head)                                        \
    { NULL }

/*
 * 定义链表的链域。 
 * type: 结点类型。
 */
#define SLIST_ENTRY(type)                                                   \
struct {                                                                    \
    struct type *sle_next;  /* next element */                              \
}

/*
 * Singly-linked List functions.
 * 初始化头结点。 
 * head: 表头结点。
 */
#define SLIST_INIT(head) do {                                               \
    (head)->slh_first = NULL;                                               \
} while (/*CONSTCOND*/0)

/*
 * 将结点elm插入到结点slistelm后面。 
 * slistelm:链表中某结点。 
 * elm:要插入的结点。 
 * field:链表中链域的名称。
*/
#define SLIST_INSERT_AFTER(slistelm, elm, field) do {                       \
    (elm)->field.sle_next = (slistelm)->field.sle_next;                     \
    (slistelm)->field.sle_next = (elm);                                     \
} while (/*CONSTCOND*/0)

/*
 * 将结点elm插入到头结点head后面。 
 * head: 表头结点。 
 * elm:要插入的结点。 
 * field:链表中链域的名称。
*/
#define SLIST_INSERT_HEAD(head, elm, field) do {                            \
    (elm)->field.sle_next = (head)->slh_first;                              \
    (head)->slh_first = (elm);                                              \
} while (/*CONSTCOND*/0)

/*
 * 移除将表头结点下面一个结点。 
 * head: 表头结点。 
 * field:链表中链域的名称。
*/
#define SLIST_REMOVE_HEAD(head, field) do {                                 \
    (head)->slh_first = (head)->slh_first->field.sle_next;                  \
} while (/*CONSTCOND*/0)

/*
* 移除将elm结点,elm结点一定要是链表中一结点。 
* head: 表头结点。 
* elm:某结点。 
* type: 结点类型。 
* field:链表中链域的名称。
*/
#define SLIST_REMOVE(head, elm, type, field) do {                           \
    if ((head)->slh_first == (elm)) {                                       \
        SLIST_REMOVE_HEAD((head), field);                                   \
    }                                                                       \
    else {                                                                  \
        struct type *curelm = (head)->slh_first;                            \
        while(curelm->field.sle_next != (elm))                              \
            curelm = curelm->field.sle_next;                                \
        curelm->field.sle_next =                                            \
            curelm->field.sle_next->field.sle_next;                         \
    }                                                                       \
} while (/*CONSTCOND*/0)

/*
* 遍历链表,相当于for循环。 
* var: 结点类型的变量名称。 
* head: 表头结点。 
* field:链表中链域的名称。
*/
#define SLIST_FOREACH(var, head, field)                                     \
    for ((var) = SLIST_FIRST((head));                                       \
        (var);                                                              \
        (var) = SLIST_NEXT((var), field) )

#define SLIST_FOREACH_PREVPTR(var, varp, head, field)                       \
    for ((varp) = &SLIST_FIRST((head));                                     \
        ((var) = *(varp)) != NULL;                                          \
        (varp) = &SLIST_NEXT((var), field) )

/*
 * Singly-linked List access methods.
 */
/*判断链表是否为空。 
* head: 表头结点。
*/
#define SLIST_EMPTY(head)       ((head)->slh_first == NULL)
/*
* 访问链表里的第一个元素。 
* head: 表头结点。
*/
#define SLIST_FIRST(head)       ((head)->slh_first)
/*
* 访问elm结点后一个元素。 
* elm:某结点。 
* field:链表中链域的名称。
*/
#define SLIST_NEXT(elm, field)  ((elm)->field.sle_next)

简单例子

struct SListItem
{
    int data;
    SLIST_ENTRY(SListItem) entry;
};
/*
 struct SListItem
 {
    int data;
    struct {
        struct SListItem* sle_next;
    } entry;
 }
 */
void slist_demo()
{
    struct SListItem* item = NULL;
    SLIST_HEAD(SListHead, SListItem) shead;
    /*
     struct SListHead {
         struct SListItem* slh_first;
     } shead;
     */
    SLIST_INIT(&shead);
 
    item = (struct SListItem*)malloc(sizeof(struct SListItem));
    item->data = 1;
 
    SLIST_INSERT_HEAD(&shead, item, entry);
    /*
     item->entry.sle_next = (&shead)->slh_first;
     (&shead)->slh_first = item;
     */
 
    item = (struct SListItem*)malloc(sizeof(struct SListItem));
    item->data = 2;
 
    SLIST_INSERT_HEAD(&shead, item, entry);
    /*
     item->entry.sle_next = (&shead)->slh_first;
     (&shead)->slh_first = item;
     */
 
    SLIST_FOREACH(item, &shead, entry){
        printf("%d ", item->data);
    }
    /*
     for(item = (&shead)->slh_first; item; item = item->entry.sle_next){
        ...
     }
     */
    printf("\n");
 
    while(!SLIST_EMPTY(&shead)){
        item = SLIST_FIRST(&shead);
        printf("remove %d\n", item->data);
        SLIST_REMOVE(&shead, item, SListItem, entry);
        free(item);
    }
    /*
     while(!((&shead)->slh_first == NULL)){
         item = (&shead)->slh_first;
         ...
         (&shead)->slh_first = (&shead)->slh_first->entry.sle_next;
         ...
     }
     */
}
/*结果
2 1
remove 2
remove 1
*/

STAILQ

STAILQ 是 Singly-linked Tail queue 的缩写,意为单向有尾链表。有尾链表可作队列使用。

sys/queue.h

有尾链表虽然为一些尾部操作提供了便捷的操作,但是可执行文件比无尾链表增加了约15%的大小,且牺牲了约20%的执行速度。

/*
 * Singly-linked Tail queue declarations.
 */
#define STAILQ_HEAD(name, type)                                             \
struct name {                                                               \
    struct type *stqh_first;    /* first element */                         \
    struct type **stqh_last;    /* addr of last next element */             \
}

#define STAILQ_HEAD_INITIALIZER(head)                                       \
    { NULL, &(head).stqh_first }

#define STAILQ_ENTRY(type)                                                  \
struct {                                                                    \
    struct type *stqe_next; /* next element */                              \
}

/*
 * Singly-linked Tail queue functions.
 */
#define STAILQ_INIT(head) do {                                              \
    (head)->stqh_first = NULL;                                              \
    (head)->stqh_last = &(head)->stqh_first;                                \
} while (/*CONSTCOND*/0)

#define STAILQ_INSERT_HEAD(head, elm, field) do {                           \
    if (((elm)->field.stqe_next = (head)->stqh_first) == NULL)              \
        (head)->stqh_last = &(elm)->field.stqe_next;                        \
    (head)->stqh_first = (elm);                                             \
} while (/*CONSTCOND*/0)

#define STAILQ_INSERT_TAIL(head, elm, field) do {                           \
    (elm)->field.stqe_next = NULL;                                          \
    *(head)->stqh_last = (elm);                                             \
    (head)->stqh_last = &(elm)->field.stqe_next;                            \
} while (/*CONSTCOND*/0)

#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do {                 \
    if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)      \
        (head)->stqh_last = &(elm)->field.stqe_next;                        \
    (listelm)->field.stqe_next = (elm);                                     \
} while (/*CONSTCOND*/0)

#define STAILQ_REMOVE_HEAD(head, field) do {                                \
    if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
        (head)->stqh_last = &(head)->stqh_first;                            \
} while (/*CONSTCOND*/0)

#define STAILQ_REMOVE(head, elm, type, field) do {                          \
    if ((head)->stqh_first == (elm)) {                                      \
        STAILQ_REMOVE_HEAD((head), field);                                  \
    } else {                                                                \
        struct type *curelm = (head)->stqh_first;                           \
        while (curelm->field.stqe_next != (elm))                            \
            curelm = curelm->field.stqe_next;                               \
        if ((curelm->field.stqe_next =                                      \
            curelm->field.stqe_next->field.stqe_next) == NULL)              \
                (head)->stqh_last = &(curelm)->field.stqe_next;             \
    }                                                                       \
} while (/*CONSTCOND*/0)

#define STAILQ_FOREACH(var, head, field)                                    \
    for ((var) = ((head)->stqh_first);                                      \
        (var);                                                              \
        (var) = ((var)->field.stqe_next))

#define STAILQ_CONCAT(head1, head2) do {                                    \
    if (!STAILQ_EMPTY((head2))) {                                           \
        *(head1)->stqh_last = (head2)->stqh_first;                          \
        (head1)->stqh_last = (head2)->stqh_last;                            \
        STAILQ_INIT((head2));                                               \
    }                                                                       \
} while (/*CONSTCOND*/0)

/*
 * Singly-linked Tail queue access methods.
 */
#define STAILQ_EMPTY(head)          ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head)          ((head)->stqh_first)
#define STAILQ_NEXT(elm, field)     ((elm)->field.stqe_next)


LIST

LIST是双向无尾链表。

sys/queue.h

双向链表有前向的指针,因此可以执行一些前向操作,而且无需遍历链表便可以删除一些节点。

/*
 * List definitions.
 * 定义表头结点。 
 * name: 表头结点名。 
 * type: 结点类型。
 */
#define LIST_HEAD(name, type)                                               \
struct name {                                                               \
    struct type *lh_first;  /* first element */                             \
}

/*
 * 初始化头结点。 
 * head: 表头结点。
*/
#define LIST_HEAD_INITIALIZER(head)                                         \
    { NULL }

/*
 * 定义链表的链域。 
 * type: 结点类型。
*/
#define LIST_ENTRY(type)                                                    \
struct {                                                                    \
    struct type *le_next;   /* next element */                              \
    struct type **le_prev;  /* address of previous next element */          \
}

/*
 * List functions.
 * 初始化头结点。 
 * head: 表头结点。
 */
#define LIST_INIT(head) do {                                                \
    (head)->lh_first = NULL;                                                \
} while (/*CONSTCOND*/0)

/*
 * 将结点elm插入到结点listelm后面。 
 * listelm:链表中某结点。 
 * elm:要插入的结点。 
 * field:链表中链域的名称。
*/
#define LIST_INSERT_AFTER(listelm, elm, field) do {                         \
    if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)          \
        (listelm)->field.le_next->field.le_prev =                           \
            &(elm)->field.le_next;                                          \
    (listelm)->field.le_next = (elm);                                       \
    (elm)->field.le_prev = &(listelm)->field.le_next;                       \
} while (/*CONSTCOND*/0)

/*
 * 将结点elm插入到结点listelm前面。 
 * listelm:链表中某结点。 
 * elm:要插入的结点。 
 * field:链表中链域的名称。
*/
#define LIST_INSERT_BEFORE(listelm, elm, field) do {                        \
    (elm)->field.le_prev = (listelm)->field.le_prev;                        \
    (elm)->field.le_next = (listelm);                                       \
    *(listelm)->field.le_prev = (elm);                                      \
    (listelm)->field.le_prev = &(elm)->field.le_next;                       \
} while (/*CONSTCOND*/0)

/*
 * 将结点elm插入到头结点head后面。 
 * head: 表头结点。 
 * elm:要插入的结点。 
 * field:链表中链域的名称。
*/
#define LIST_INSERT_HEAD(head, elm, field) do {                             \
    if (((elm)->field.le_next = (head)->lh_first) != NULL)                  \
        (head)->lh_first->field.le_prev = &(elm)->field.le_next;            \
    (head)->lh_first = (elm);                                               \
    (elm)->field.le_prev = &(head)->lh_first;                               \
} while (/*CONSTCOND*/0)

/*
 * 移除将elm结点。 
 * elm:某结点。 
 * field:链表中链域的名称。
*/
#define LIST_REMOVE(elm, field) do {                                        \
    if ((elm)->field.le_next != NULL)                                       \
        (elm)->field.le_next->field.le_prev =                               \
            (elm)->field.le_prev;                                           \
    *(elm)->field.le_prev = (elm)->field.le_next;                           \
} while (/*CONSTCOND*/0)

/*遍历链表,相当于for循环。 
 * var: 结点类型的变量名称。 
 * head: 表头结点。 
 * field:链表中链域的名称。
*/
#define LIST_FOREACH(var, head, field)                                      \
    for ((var) = ((head)->lh_first);                                        \
        (var);                                                              \
        (var) = ((var)->field.le_next))

/*
 * List access methods.
 */
 /*
  * 判断链表是否为空。 
  * head: 表头结点。
 */
#define LIST_EMPTY(head)        ((head)->lh_first == NULL)
/*
 * 访问链表里的第一个元素。 
 * head: 表头结点。
*/
#define LIST_FIRST(head)        ((head)->lh_first)
/*
 * 访问elm结点后一个元素。 
 * elm:某结点。 
 * field:链表中链域的名称。
*/
#define LIST_NEXT(elm, field)   ((elm)->field.le_next)
/*
 * 访问elm结点前一个元素。
*/
#define LIST_PRE(elm, field) \
	(((elm)->field.le_pre) != &elm ? *((elm)->field.le_pre) : NULL)

简单例子

struct ListItem
{
    int data;
    LIST_ENTRY(ListItem) entry;
};
/*
struct ListItem
{
    int data;
    struct{
        struct ListItem* le_next;
        struct ListItem** le_prev;
    } entry;
};
*/
void list_demo()
{
    struct ListItem* item = NULL;
    
    LIST_HEAD(ListHead, ListItem) lhead;
    /*
    struct ListHead {
        struct ListItem* lh_first;
    } lhead;
    */
    LIST_INIT(&lhead);
    /*
    do{
         (&lhead)->lh_first = NULL;
    }while(0);
    */
 
    item = (struct ListItem*)malloc(sizeof(struct ListItem));
    item->data = 1;
 
    LIST_INSERT_HEAD(&lhead, item, entry);
    
    item = (struct ListItem*)malloc(sizeof(struct ListItem));
    item->data = 2;
    
    LIST_INSERT_HEAD(&lhead, item, entry);
    /*
    do{
        if(((item)->entry.le_next = (&lhead)->lh_first) != NULL)
            (&lhead)->lh_first->entry.le_pre = &(elm)->entry.le_next;
        (&lhead)->lh_first = (item);
        (item)->entry.le_prev = &(&lhead)->lh_first;
    }while(0);
    */
    LIST_FOREACH(item, &lhead, entry){
        printf("%d ", item->data);
    }
    /*
    for ((item) = ((&lhead)->lh_first);
        (item);
        (item) = ((item)->entry.le_next)){
        ...
    }    
    */
    printf("\n");
 
    while(!LIST_EMPTY(&lhead)){
        item = LIST_FIRST(&lhead);
        printf("remove %d\n", item->data);
        LIST_REMOVE(item, entry);
        free(item);
    }
    /*
    while(!((&lhead)->lh_first == NULL)){
        item = ((&lhead)->lh_first);
        ...
        do{
          if ((item)->entry.le_next != NULL)                \
            (item)->entry.le_next->entry.le_prev =             \
                (item)->entry.le_prev;                \
          *(item)->entry.le_prev = (item)->entry.le_next;            \
        } while (0);
        ...
    }
    */
}
/*
结果
2 1
remove 2
remove 1
*/

TAILQ

TAILQ 是 Tail queue 的缩写,意为双向有尾链表。有尾链表可作队列使用。

sys/queue.h

双向有尾链表兼具了双向链表和有尾链表的特点。

/*
 * Tail queue definitions.
 */
#define TAILQ_HEAD(name, type)                                              \
struct name {                                                               \
    struct type *tqh_first;     /* first element */                         \
    struct type **tqh_last;     /* addr of last next element */             \
}

#define TAILQ_HEAD_INITIALIZER(head)                                        \
    { NULL, &(head).tqh_first }

#define TAILQ_ENTRY(type)                                                   \
struct {                                                                    \
    struct type *tqe_next;      /* next element */                          \
    struct type **tqe_prev;     /* address of previous next element */      \
}

/*
 * Tail queue functions.
 */
#define TAILQ_INIT(head) do {                                               \
    (head)->tqh_first = NULL;                                               \
    (head)->tqh_last = &(head)->tqh_first;                                  \
} while (/*CONSTCOND*/0)

#define TAILQ_INSERT_HEAD(head, elm, field) do {                            \
    if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)                \
        (head)->tqh_first->field.tqe_prev = &(elm)->field.tqe_next;         \
    else                                                                    \
        (head)->tqh_last = &(elm)->field.tqe_next;                          \
    (head)->tqh_first = (elm);                                              \
    (elm)->field.tqe_prev = &(head)->tqh_first;                             \
} while (/*CONSTCOND*/0)

#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 (/*CONSTCOND*/0)

#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {                  \
    if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)        \
        (elm)->field.tqe_next->field.tqe_prev = &(elm)->field.tqe_next;     \
    else                                                                    \
        (head)->tqh_last = &(elm)->field.tqe_next;                          \
    (listelm)->field.tqe_next = (elm);                                      \
    (elm)->field.tqe_prev = &(listelm)->field.tqe_next;                     \
} while (/*CONSTCOND*/0)

#define TAILQ_INSERT_BEFORE(listelm, elm, field) do {                       \
    (elm)->field.tqe_prev = (listelm)->field.tqe_prev;                      \
    (elm)->field.tqe_next = (listelm);                                      \
    *(listelm)->field.tqe_prev = (elm);                                     \
    (listelm)->field.tqe_prev = &(elm)->field.tqe_next;                     \
} while (/*CONSTCOND*/0)

#define TAILQ_REMOVE(head, elm, field) do {                                 \
    if (((elm)->field.tqe_next) != NULL)                                    \
        (elm)->field.tqe_next->field.tqe_prev = (elm)->field.tqe_prev;      \
    else                                                                    \
        (head)->tqh_last = (elm)->field.tqe_prev;                           \
    *(elm)->field.tqe_prev = (elm)->field.tqe_next;                         \
} while (/*CONSTCOND*/0)

#define TAILQ_FOREACH(var, head, field)                                     \
    for ((var) = ((head)->tqh_first);                                       \
        (var);                                                              \
        (var) = ((var)->field.tqe_next))

#define TAILQ_FOREACH_REVERSE(var, head, headname, field)                   \
    for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));    \
        (var);                                                              \
        (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))

#define TAILQ_CONCAT(head1, head2, field) do {                              \
    if (!TAILQ_EMPTY(head2)) {                                              \
        *(head1)->tqh_last = (head2)->tqh_first;                            \
        (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last;             \
        (head1)->tqh_last = (head2)->tqh_last;                              \
        TAILQ_INIT((head2));                                                \
    }                                                                       \
} while (/*CONSTCOND*/0)

/*
 * Tail queue access methods.
 */
#define TAILQ_EMPTY(head)       ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head)       ((head)->tqh_first)
#define TAILQ_NEXT(elm, field)  ((elm)->field.tqe_next)

#define TAILQ_LAST(head, headname)                                          \
    (*(((struct headname *)((head)->tqh_last))->tqh_last))

#define TAILQ_PREV(elm, headname, field)                                    \
    (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))


CIRCLEQ

CIRCLEQ 是 Circular queue 的缩写,意为循环链表。

sys/queue.h

/*
 * Circular queue definitions.
 */
#define CIRCLEQ_HEAD(name, type)                                            \
struct name {                                                               \
    struct type *cqh_first;     /* first element */                         \
    struct type *cqh_last;      /* last element */                          \
}

#define CIRCLEQ_HEAD_INITIALIZER(head)                                      \
    { (void *)&head, (void *)&head }

#define CIRCLEQ_ENTRY(type)                                                 \
struct {                                                                    \
    struct type *cqe_next;      /* next element */                          \
    struct type *cqe_prev;      /* previous element */                      \
}

/*
 * Circular queue functions.
 */
#define CIRCLEQ_INIT(head) do {                                             \
    (head)->cqh_first = (void *)(head);                                     \
    (head)->cqh_last = (void *)(head);                                      \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {                \
    (elm)->field.cqe_next = (listelm)->field.cqe_next;                      \
    (elm)->field.cqe_prev = (listelm);                                      \
    if ((listelm)->field.cqe_next == (void *)(head))                        \
        (head)->cqh_last = (elm);                                           \
    else                                                                    \
        (listelm)->field.cqe_next->field.cqe_prev = (elm);                  \
    (listelm)->field.cqe_next = (elm);                                      \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {               \
    (elm)->field.cqe_next = (listelm);                                      \
    (elm)->field.cqe_prev = (listelm)->field.cqe_prev;                      \
    if ((listelm)->field.cqe_prev == (void *)(head))                        \
        (head)->cqh_first = (elm);                                          \
    else                                                                    \
        (listelm)->field.cqe_prev->field.cqe_next = (elm);                  \
    (listelm)->field.cqe_prev = (elm);                                      \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {                          \
    (elm)->field.cqe_next = (head)->cqh_first;                              \
    (elm)->field.cqe_prev = (void *)(head);                                 \
    if ((head)->cqh_last == (void *)(head))                                 \
        (head)->cqh_last = (elm);                                           \
    else                                                                    \
        (head)->cqh_first->field.cqe_prev = (elm);                          \
    (head)->cqh_first = (elm);                                              \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {                          \
    (elm)->field.cqe_next = (void *)(head);                                 \
    (elm)->field.cqe_prev = (head)->cqh_last;                               \
    if ((head)->cqh_first == (void *)(head))                                \
        (head)->cqh_first = (elm);                                          \
    else                                                                    \
        (head)->cqh_last->field.cqe_next = (elm);                           \
    (head)->cqh_last = (elm);                                               \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_REMOVE(head, elm, field) do {                               \
    if ((elm)->field.cqe_next == (void *)(head))                            \
        (head)->cqh_last = (elm)->field.cqe_prev;                           \
    else                                                                    \
        (elm)->field.cqe_next->field.cqe_prev = (elm)->field.cqe_prev;      \
    if ((elm)->field.cqe_prev == (void *)(head))                            \
        (head)->cqh_first = (elm)->field.cqe_next;                          \
    else                                                                    \
        (elm)->field.cqe_prev->field.cqe_next = (elm)->field.cqe_next;      \
} while (/*CONSTCOND*/0)

#define CIRCLEQ_FOREACH(var, head, field)                                   \
    for ((var) = ((head)->cqh_first);                                       \
        (var) != (const void *)(head);                                      \
        (var) = ((var)->field.cqe_next))

#define CIRCLEQ_FOREACH_REVERSE(var, head, field)                           \
    for ((var) = ((head)->cqh_last);                                        \
        (var) != (const void *)(head);                                      \
        (var) = ((var)->field.cqe_prev))

/*
 * Circular queue access methods.
 */
#define CIRCLEQ_EMPTY(head)         ((head)->cqh_first == (void *)(head))
#define CIRCLEQ_FIRST(head)         ((head)->cqh_first)
#define CIRCLEQ_LAST(head)          ((head)->cqh_last)
#define CIRCLEQ_NEXT(elm, field)    ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field)    ((elm)->field.cqe_prev)

#define CIRCLEQ_LOOP_NEXT(head, elm, field)                                 \
    (((elm)->field.cqe_next == (void *)(head))                              \
        ? ((head)->cqh_first)                                               \
        : (elm->field.cqe_next))

#define CIRCLEQ_LOOP_PREV(head, elm, field)                                 \
    (((elm)->field.cqe_prev == (void *)(head))                              \
        ? ((head)->cqh_last)                                                \
        : (elm->field.cqe_prev))


SIMPLEQ

  • 简单来说,就是表对有两个链域,分别指向头和尾。

  • simple queue 定义(具体说明不再写,可以参考list的,或者就直接展开宏)

/*
 * Simple queue definitions.
 */
#define SIMPLEQ_HEAD(name, type)					\
struct name {								\
	struct type *sqh_first;	/* first element */			\
	struct type **sqh_last;	/* addr of last next element */		\
}

#define SIMPLEQ_HEAD_INITIALIZER(head)					\
	{ NULL, &(head).sqh_first }

#define SIMPLEQ_ENTRY(type)						\
struct {								\
	struct type *sqe_next;	/* next element */			\
}

/*
 * Simple queue access methods.
 */
#define	SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
#define	SIMPLEQ_END(head)	    NULL
#define	SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define	SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)

#define SIMPLEQ_FOREACH(var, head, field)				\
	for((var) = SIMPLEQ_FIRST(head);				\
	    (var) != SIMPLEQ_END(head);					\
	    (var) = SIMPLEQ_NEXT(var, field))

/*
 * Simple queue functions.
 */
#define	SIMPLEQ_INIT(head) do {						\
	(head)->sqh_first = NULL;					\
	(head)->sqh_last = &(head)->sqh_first;				\
} while (0)

#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
	if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
		(head)->sqh_last = &(elm)->field.sqe_next;		\
	(head)->sqh_first = (elm);					\
} while (0)

#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
	(elm)->field.sqe_next = NULL;					\
	*(head)->sqh_last = (elm);					\
	(head)->sqh_last = &(elm)->field.sqe_next;			\
} while (0)

#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
	if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
		(head)->sqh_last = &(elm)->field.sqe_next;		\
	(listelm)->field.sqe_next = (elm);				\
} while (0)

#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do {			\
	if (((head)->sqh_first = (elm)->field.sqe_next) == NULL)	\
		(head)->sqh_last = &(head)->sqh_first;			\
} while (0)

例程

本例程展示了单向无尾链表的创建、插入、读取、删除、迭代、销毁等操作。并使用了归并排序对链表实现排序。

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/queue.h>

typedef struct num_node                             /* 链表节点结构体 */
{
    SLIST_ENTRY(num_node) field;
    uint32_t num;
} num_node;

typedef SLIST_HEAD(num_head, num_node) num_head;    /* 链表头结构体 */

/* 合并两个链表 */
static num_node *merge(num_node *node1, num_node *node2)
{
    if (node1 == NULL) {return node2;}
    if (node2 == NULL) {return node1;}

    num_node *res, *ptr;

    if(node1->num < node2->num) {
        res = node1;
        node1 = SLIST_NEXT(node1, field);
    }
    else {
        res = node2;
        node2 = SLIST_NEXT(node2, field);
    }

    ptr = res;

    while (node1 != NULL && node2 != NULL) {
        if (node1->num < node2->num) {
            SLIST_NEXT(ptr, field) = node1;
            node1 = SLIST_NEXT(node1, field);
        }
        else {
            SLIST_NEXT(ptr, field) = node2;
            node2 = SLIST_NEXT(node2, field);
        }
        ptr = SLIST_NEXT(ptr, field);
    }

    if      (node1 != NULL) {SLIST_NEXT(ptr, field) = node1;}
    else if (node2 != NULL) {SLIST_NEXT(ptr, field) = node2;}

    return res;
}

/* 对链表节点进行归并排序 */
static num_node *mergeSort(num_node *node)
{
    if (node==NULL || SLIST_NEXT(node,field)==NULL) { 
        return node;
    }

    num_node *fast = node;
    num_node *slow = node;
    while (SLIST_NEXT(fast, field)!=NULL) {
        if (SLIST_NEXT(SLIST_NEXT(fast,field), field) == NULL) {
            break;
        }
        fast = SLIST_NEXT(SLIST_NEXT(fast,field), field);
        slow = SLIST_NEXT(slow, field);
    }

    fast = slow;
    slow = SLIST_NEXT(slow, field);
    SLIST_NEXT(fast,field) = NULL;
    fast = mergeSort(node);
    slow = mergeSort(slow);
    return merge(fast, slow);
}

/* 对链表头进行归并排序 */
void num_mergeSort(num_head *head)
{
    SLIST_FIRST(head) = mergeSort(SLIST_FIRST(head));
}

int main(void)
{
    /* 从堆空间申请链表表头并初始化 */
    num_head *p_head = malloc(sizeof(num_head));
    SLIST_INIT(p_head);

    /* 为链表添加10个0~100的随机数 */
    num_node *elm;
    for (int i=0; i<10; ++i) {
        elm = malloc(sizeof(num_node));
        elm->num = rand() % 100;
        SLIST_INSERT_HEAD(p_head, elm, field);
    }

    /* 打印排序前的链表 */
    printf("Before sort:\n");
    SLIST_FOREACH (elm, p_head, field) {
        printf("addr = %p, num = %d\n", elm, elm->num);
    }

    /* 归并排序函数 */
    num_mergeSort(p_head);

    /* 打印排序后的链表 */
    printf("After sort:\n");
    SLIST_FOREACH (elm, p_head, field) {
        printf("addr = %p, num = %d\n", elm, elm->num);
    }

    /* 销毁链表释放空间 */
    while (!SLIST_EMPTY(p_head)) {
        num_node *ptr = SLIST_FIRST(p_head);
        SLIST_REMOVE_HEAD(p_head, field);
        free(ptr);
    }
    free(p_head);

    return 0;
}

运行结果

Before sort:
addr = 0x55bd1a2223a0, num = 21
addr = 0x55bd1a222380, num = 49
addr = 0x55bd1a222360, num = 92
addr = 0x55bd1a222340, num = 86
addr = 0x55bd1a222320, num = 35
addr = 0x55bd1a222300, num = 93
addr = 0x55bd1a2222e0, num = 15
addr = 0x55bd1a2222c0, num = 77
addr = 0x55bd1a2222a0, num = 86
addr = 0x55bd1a222280, num = 83
After sort:
addr = 0x55bd1a2222e0, num = 15
addr = 0x55bd1a2223a0, num = 21
addr = 0x55bd1a222320, num = 35
addr = 0x55bd1a222380, num = 49
addr = 0x55bd1a2222c0, num = 77
addr = 0x55bd1a222280, num = 83
addr = 0x55bd1a2222a0, num = 86
addr = 0x55bd1a222340, num = 86
addr = 0x55bd1a222360, num = 92
addr = 0x55bd1a222300, num = 93

《关于libevent与FreeBSD内核中TAILQ队列的理解》
《libevent源码分析-- queue.h中TAILQ_QUEUE的理解》
《libevent源码之TAILQ详解》
《 QEMU代码中的QLIST》
《Libevent源码分析-----TAILQ_QUEUE队列》

上一篇:C++学习笔记


下一篇:基于麻雀算法优化的核极限学习机(KELM)回归预测 -附代码