queue.h是Linux、FreeBSD中的(de)一個頭文件。
FreeBSD:FreeBSD 是一(yi)種(zhong)類(lei) UNIX操作系(xi)統。
這(zhe)是一個(ge)很實用(yong)的頭文件,因(yin)為(wei)這(zhe)個(ge)頭文件里(li)全是宏(hong)定義操作,所以(yi)其不僅可以(yi)使用(yong)在(zai)Linux/嵌入式Linux項目中(zhong),也可以(yi)很方便地(di)使用(yong)在(zai)單(dan)片(pian)機項目中(zhong)。
它使用宏(hong)實現了如(ru)下(xia)數據(ju)結構:
- SLIST:單(dan)向無尾(wei)鏈表
- LIST:雙向無尾鏈表
- STAILQ:單向有尾鏈表(可作隊列(lie)使用)
- TAILQ:雙(shuang)向有尾(wei)鏈(lian)表(可作(zuo)隊列使用)
所有的數據(ju)結(jie)構都支持(chi)如下功能:
- 在鏈(lian)表頭插(cha)入(ru)節點
- 在任意節(jie)點后插入節(jie)點
- 刪除節點
- 遍(bian)歷節點(dian)
我們可以在Linux系(xi)統的如下(xia)路(lu)徑(jing)中找到這個頭文件(jian):
/usr/include/sys/queue.h
也可以通過如下網(wang)址查看:
//code.woboq.org/userspace/glibc/misc/sys/queue.h.html
sys/queue.h的(de)使用(yong)
下面(mian)我們基于(yu)SLIST來演示其(qi)使用。
SLIST相關(guan)宏定義:
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) do { \
(head)->slh_first = NULL; \
} while (/*CONSTCOND*/0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (/*CONSTCOND*/0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (/*CONSTCOND*/0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (/*CONSTCOND*/0)
#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)
#define SLIST_FOREACH(var, head, field) \
for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
/*
* Singly-linked List access methods.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
下面(mian)我們通過(guo)實例來(lai)操作。
首先,創建鏈表(biao)頭(tou)節(jie)點、其它節(jie)點結構體(ti),用到SLIST_HEAD與SLIST_ENTRY這兩(liang)個宏(hong)定義:
#define ELEM_TYPE int
/* 鏈表節點 */
typedef struct node
{
ELEM_TYPE data;
SLIST_ENTRY(node) field;
}node_st;
/* 鏈表頭 */
typedef SLIST_HEAD(head, node) head_st;
鏈表數據域(yu)類型我(wo)們定義(yi)為(wei)int,field表示的是指針域(yu)。
① 創建一(yi)個(ge)頭結點:
/* 創建鏈表頭節點并初始化 */
head_st *head = (head_st *)malloc(sizeof(head_st));
SLIST_INIT(head);
頭節點(dian)(dian):不存任何(he)數據的(de)空節點(dian)(dian),通常作(zuo)為鏈表的(de)第一個節點(dian)(dian)。
② 在鏈(lian)表(biao)頭部分別插入(ru)節點node1、node2:
/* 頭插法插入一個節點node1 */
node_st *node1 = (node_st *)malloc(sizeof(node_st));
node1->data = 1;
SLIST_INSERT_HEAD(head, node1, field);
/* 頭插法插入一個節點node2 */
node_st *node2 = (node_st *)malloc(sizeof(node_st));
node2->data = 2;
SLIST_INSERT_HEAD(head, node2, field);
頭指針:永遠指向鏈(lian)表第一個(ge)節點(dian)的位(wei)置。
SLIST_INSERT_HEAD是從鏈(lian)表頭部插入(ru)節(jie)點,新節(jie)點總是從頭結點之(zhi)后插入(ru)。
③ 在鏈表(biao)節(jie)(jie)點node2之后插入節(jie)(jie)點node3:
node_st *node3 = (node_st *)malloc(sizeof(node_st));
node3->data = 3;
SLIST_INSERT_AFTER(node2, node3, field);
SLIST_INSERT_AFTER是從指(zhi)定節(jie)點slistelm之后(hou)插入(ru)新節(jie)點elm。
④ 遍歷鏈表:
node_st *tmp_elm;
SLIST_FOREACH(tmp_elm, head, field)
{
printf("%d ", tmp_elm->data);
}
輸出為tmp_elm,訪問tmp_elm即可。
⑤ 刪除某(mou)個(ge)節(jie)點node2
SLIST_REMOVE(head, node2, node, field);
free(node2);
node2 = NULL;
⑥ 銷(xiao)毀整(zheng)個鏈表
while (!SLIST_EMPTY(head))
{
node_st *p = SLIST_FIRST(head);
SLIST_REMOVE_HEAD(head, field);
free(p);
p = NULL;
}
free(head);
head = NULL;
完整測試代碼:
#include
#include
#include
#define ELEM_TYPE int
/* 鏈表節點 */
typedefstruct node
{
ELEM_TYPE data;
SLIST_ENTRY(node) field;
}node_st;
/* 鏈表頭 */
typedef SLIST_HEAD(head, node) head_st;
int main(void)
{
/* 創建鏈表頭節點并初始化 */
head_st *head = (head_st *)malloc(sizeof(head_st));
SLIST_INIT(head);
/* 頭插法插入一個節點node1 */
node_st *node1 = (node_st *)malloc(sizeof(node_st));
node1->data = 1;
SLIST_INSERT_HEAD(head, node1, field);
/* 頭插法插入一個節點node2 */
node_st *node2 = (node_st *)malloc(sizeof(node_st));
node2->data = 2;
SLIST_INSERT_HEAD(head, node2, field);
/* 遍歷打印當前鏈表節點 */
printf("list:\n");
node_st *tmp_elm;
SLIST_FOREACH(tmp_elm, head, field)
{
printf("%d ", tmp_elm->data);
}
printf("\n");
/* 尾插法插入一個節點node3 */
printf("insert node3:\n");
node_st *node3 = (node_st *)malloc(sizeof(node_st));
node3->data = 3;
SLIST_INSERT_AFTER(node2, node3, field);
SLIST_FOREACH(tmp_elm, head, field)
{
printf("%d ", tmp_elm->data);
}
printf("\n");
/* 刪除node2 */
printf("delete node2:\n");
SLIST_REMOVE(head, node2, node, field);
free(node2);
node2 = NULL;
SLIST_FOREACH(tmp_elm, head, field)
{
printf("%d ", tmp_elm->data);
}
printf("\n");
/* 銷毀鏈表 */
while (!SLIST_EMPTY(head))
{
node_st *p = SLIST_FIRST(head);
SLIST_REMOVE_HEAD(head, field);
free(p);
p = NULL;
}
free(head);
head = NULL;
return0;
}
編譯、運行:
運行結果(guo)與我們上面(mian)分析(xi)的一致。
本次我們只分享queue.h里最簡單的(de)數(shu)據(ju)結(jie)構。其它幾種(zhong)數(shu)據(ju)結(jie)構的(de)使用例子及相關宏說明可以通過man命令查看(kan)。
man是Linux下的幫(bang)助命令。
我(wo)們輸入 man queue
即(ji)可查到queue.h的(de)相關說明:
可以(yi)看到,man命令很強大(da),可查到queue的幫助說明(ming)很詳(xiang)細(xi),有宏的說明(ming)及(ji)使用示(shi)例等。