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当中,无需编译为库文件。
每种结构都支持基本的操作:
- 在链表头插入节点
- 在任意的节点后插入节点
- 移除链表头后的节点
- 前向迭代遍历链表
功能支持 | 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 的缩写,意为单向无尾链表。
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 的缩写,意为单向有尾链表。有尾链表可作队列使用。
有尾链表虽然为一些尾部操作提供了便捷的操作,但是可执行文件比无尾链表增加了约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是双向无尾链表。
双向链表有前向的指针,因此可以执行一些前向操作,而且无需遍历链表便可以删除一些节点。
/*
* 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 的缩写,意为双向有尾链表。有尾链表可作队列使用。
双向有尾链表兼具了双向链表和有尾链表的特点。
/*
* 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 的缩写,意为循环链表。
/*
* 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队列》