- struct ngx_queue_s {
- ngx_queue_t *prev;
- ngx_queue_t *next;
- };
-
结构成员:
ngx_queue_t *prev;前驱指针
ngx_queue_t *next;后继指针
- define ngx_queue_init(q) \
- (q)->prev = q; \
- (q)->next = q
-
-
- #define ngx_queue_empty(h) \
- (h == (h)->prev)
-
- #define ngx_queue_sentinel(h) \
- (h)
-
-
-
- #define ngx_queue_head(h) \
- (h)->next
-
-
- #define ngx_queue_last(h) \
- (h)->prev
1.初始化头结点 将两个指针指向自身
2.检测前驱结点
3返回头结点(哨兵:)
4.头结点和尾结点
#define ngx_queue_insert_head(h, x)
- #define ngx_queue_insert_head(h, x)
- (x)->next = (h)->next; \
- (x)->next->prev = x; \
- (x)->prev = h; \
- (h)->next = x
-
采用一个哨兵的方法
h作为一个哨兵,x成为一个头结点
#define ngx_queue_insert_tail(h, x)
- #define ngx_queue_insert_tail(h, x) \
- (x)->prev = (h)->prev; \
- (x)->prev->next = x; \
- (x)->next = h; \
- (h)->prev = x
-
删除
- #define ngx_queue_remove(x)
- (x)->next->prev = (x)->prev; \
- (x)->prev->next = (x)->next; \
- (x)->prev = NULL; \
- (x)->next = NULL
-
- #define ngx_queue_split(h, q, n)
- (n)->prev = (h)->prev; \
- (n)->prev->next = n; \
- (n)->next = q; \
- (h)->prev = (q)->prev; \
- (h)->prev->next = h; \
- (q)->prev = n;
-
-
- #define ngx_queue_add(h, n) \
- (h)->prev->next = (n)->next; \
- (n)->next->prev = (h)->prev; \
- (h)->prev = (n)->prev; \
- (h)->prev->next = h;
1.分裂队列 h是头 q是分裂节点的界限 n为分裂完的新节点
2.合并队列 n本身的节点会抛弃
- #define ngx_queue_remove(x) \
- (x)->next->prev = (x)->prev; \
- (x)->prev->next = (x)->next
-
- #define ngx_queue_insert_after ngx_queue_insert_head
注意:
- #define ngx_queue_next(q) \
- (q)->next
-
-
- #define ngx_queue_prev(q) \
- (q)->prev
-
- gx_queue_t *
- ngx_queue_middle(ngx_queue_t *queue)
- {
- ngx_queue_t *middle, *next;
-
- middle = ngx_queue_head(queue);
-
- if (middle == ngx_queue_last(queue)) {
- return middle;
- }
-
- next = ngx_queue_head(queue);
-
- for ( ;; ) {
- middle = ngx_queue_next(middle);
-
- next = ngx_queue_next(next);
-
- if (next == ngx_queue_last(queue)) {
- return middle;
- }
-
- next = ngx_queue_next(next);
-
- if (next == ngx_queue_last(queue)) {
- return middle;
- }
- }
- }
- void queue_sort(ngx_queue_t *queue,
- ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
- {
- ngx_queue_t *q, *prev, *next;
-
- q = ngx_queue_head(queue);
-
- if (q == ngx_queue_last(queue)) {
- return;
- }
-
- for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) {
-
- prev = ngx_queue_prev(q);
- next = ngx_queue_next(q);
-
- ngx_queue_remove(q);
-
- do {
- if (cmp(prev, q) <= 0) {
- break;
- }
-
- prev = ngx_queue_prev(prev);
-
- } while (prev != ngx_queue_sentinel(queue));
-
- ngx_queue_insert_after(prev, q);
- }
- }
全是暴力算法 效率比较低 不做过多解释
引出一个知识:
双端队列是在两端都可以插入或删除元素的数据结构,在Nginx里它被实现为双向循环链表ngx_queue_t,类似标准容器std : : list。
借用Boost程序库的概念,前面的ngx_array_t和ngx_list_t属于非侵入式容器,元素无须改动即可加入容器,而 ngx_queue_t 则不同,它是侵入式容器,必须把 ngx_queue_t作为元素的一个成员,然后才能放入队列,与boost.intrusive库很接近。
- struct Xinfo
- {
- int x=0;
- ngx_queue_t queue;
- }
例子
- #include
#include - #include
- #include
- #include "ngx_queue.h"
-
- //数据定义 节点必须有ngx_queue_t
- typedef struct student
- {
- int id;
- int age;
- int weight;
- ngx_queue_t qnode;
- }student;
- //排序比较函数
- ngx_int_t stu_cmp(const ngx_queue_t *n1, const ngx_queue_t *n2)
- {
- //拿到数据
- struct student *s1 = ngx_queue_data(n1, student, qnode);
- struct student *s2 = ngx_queue_data(n2, student, qnode);
-
- return s1->id - s2->id;
- }
- //遍历
- void stu_foreach(const ngx_queue_t *queue)
- {
- ngx_queue_t *q = ngx_queue_head(queue);
-
- struct student *s = ngx_queue_data(q, student, qnode);
- if (q == ngx_queue_last(queue)) {
- return;
- }
- printf("id = %d\n",s->id);
-
- for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = ngx_queue_next(q)) {
- s = ngx_queue_data(q, student, qnode);
- printf("id = %d\n",s->id);
- }
- }
-
- int main(int argc,char *argv[])
- {
- //初始化队列
- ngx_queue_t *q = (ngx_queue_t *)calloc(1,sizeof(ngx_queue_t));
- ngx_queue_init(q);
- //初始化数据
- struct student st1 = {1,11,111};
- struct student st2 = {2,12,112};
- struct student st3 = {3,13,113};
- struct student st4 = {4,14,114};
- struct student st5 = {5,15,115};
- //头插法 将qnode插入
- ngx_queue_insert_head(q,&st2.qnode);
- ngx_queue_insert_head(q,&st4.qnode);
- ngx_queue_insert_head(q,&st1.qnode);
- ngx_queue_insert_head(q,&st5.qnode);
- ngx_queue_insert_head(q,&st3.qnode);
- //排序
- printf("================sort=============\n");
- stu_foreach(q);
- printf("\n");
- ngx_queue_sort(q,stu_cmp);
- stu_foreach(q);
- //找中间值
- printf("================middle=============\n");
- ngx_queue_t *mid = ngx_queue_middle(q);
- student *s = ngx_queue_data(mid, student, qnode);
- printf("id:%d\n",s->id);
- //分裂
- printf("================split=============\n");
- ngx_queue_t *n = (ngx_queue_t *)calloc(1,sizeof(ngx_queue_t));
- ngx_queue_init(n);
- ngx_queue_split(q,mid,n);
- printf("=old queue=\n");
- stu_foreach(q);
- printf("=new queue=\n");
- stu_foreach(n);
- //合并
- printf("================add=============\n");
- ngx_queue_add(q,n);
- stu_foreach(q);
-
- free(n);
- free(q);
-
- return 0;
- }