net小伙曾在文章【数据结构】链式线性表的几种常用用法中写过关于线性表的操作方法,重新阅读发现代码很是稚嫩,现重新整理。
一般情况下我们会使用一个结构体head来作为双向链表的头部,head有两个指针域,一个指向链表的开始,一个指向链表的末尾。双向链表的指针域也有两个,一个指向前一个节点,一个指向后一个节点。两个结构体定义如下:
1 #define TAILQ_HEAD(name, type) \ 2 struct name { \ 3 struct type *tqh_first; /* first element */ \ 4 struct type **tqh_last; /* addr of last next element */ \ 5 } 6 #define TAILQ_ENTRY(type) \ 7 struct { \ 8 struct type *tqe_next; /* next element */ \ 9 struct type **tqe_prev; /* address of previous next element */ \ 10 }
使用二级指针是为了在遍历链表和删除链表的时候,代码更具有可读性。
完整的链表拓扑如下:
接下来直接给出代码,并附上一个小例子:
1 #define TAILQ_HEAD(name, type) \ 2 struct name { \ 3 struct type *tqh_first; /* first element */ \ 4 struct type **tqh_last; /* addr of last next element */ \ 5 } 6 #define TAILQ_ENTRY(type) \ 7 struct { \ 8 struct type *tqe_next; /* next element */ \ 9 struct type **tqe_prev; /* address of previous next element */ \ 10 } 11 12 #define TAILQ_FIRST(head) ((head)->tqh_first) 13 #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 14 #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 15 #define TRASHIT(x) do {(x) = (void *)-1;} while (0) 16 17 #define TAILQ_INIT(head) do { \ 18 TAILQ_FIRST((head)) = NULL; \ 19 (head)->tqh_last = &TAILQ_FIRST((head)); \ 20 } while (0) 21 22 #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 23 if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ 24 TAILQ_FIRST((head))->field.tqe_prev = \ 25 &TAILQ_NEXT((elm), field); \ 26 else \ 27 (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 28 TAILQ_FIRST((head)) = (elm); \ 29 (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ 30 } while (0) 31 32 #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 33 TAILQ_NEXT((elm), field) = NULL; \ 34 (elm)->field.tqe_prev = (head)->tqh_last; \ 35 *(head)->tqh_last = (elm); \ 36 (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 37 } while (0) 38 39 #define TAILQ_FOREACH(var, head, field) \ 40 for ((var) = TAILQ_FIRST((head)); \ 41 (var); \ 42 (var) = TAILQ_NEXT((var), field)) 43 44 #define TAILQ_REMOVE(head, elm, field) do { \ 45 if ((TAILQ_NEXT((elm), field)) != NULL) \ 46 TAILQ_NEXT((elm), field)->field.tqe_prev = \ 47 (elm)->field.tqe_prev; \ 48 else { \ 49 (head)->tqh_last = (elm)->field.tqe_prev; \ 50 } \ 51 *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ 52 TRASHIT((elm)->field.tqe_next); \ 53 TRASHIT((elm)->field.tqe_prev); \ 54 } while (0)