nginx学习六 高级数据结构之双向链表ngx_queue_t
1 ngx_queue_t简单介绍
ngx_queue_t是nginx提供的一个轻量级的双向链表容器,它不负责存储数据,既不提供数据的内存分配。它仅仅有两个指针负责把数据链入链表。它跟stl提供的queue不同,stl提供的queue帮助用户存储数据。用户仅仅须要相容器里加入数据就可以,而ngx_queue_t,用户必须自己提供存储数据的内存,而且必须定义一种数据结构把ngx_queue_t包括在当中,然后利用ngx_queue_t提供的函数来进行对应的操作。
2 ngx_queue_t结构及其操作
2.1 ngx_queue_t
struct ngx_queue_s {
ngx_queue_t *prev;
ngx_queue_t *next;
};
ngx_queue_t仅仅提供一个指向前驱和一个指向后继的指针。结构很easy,这也是其可以通用性的原因。
2.2 操作函数
ngx_queue_init(q) //初始化链表
ngx_queue_empty(h) //推断链表是否为空
ngx_queue_insert_head(h, x) //在头部插入一个元素
ngx_queue_insert_after //在h元素前面插入一个元素
ngx_queue_insert_tail(h, x) //在h尾部插入一个元素
ngx_queue_head(h) //返回第一个元素
#define ngx_queue_last(h) //返回最后一个元素
ngx_queue_sentinel(h) //返回链表容器结构体的指针
ngx_queue_next(q) //返回下一个q的下一个元素
ngx_queue_prev(q) //返回q的前一个元素
ngx_queue_remove(x) //删除x结点
ngx_queue_split(h, q, n) //把h分为两个链表h和n,而且n的第一元素为q
ngx_queue_add(h, n) //把链表n添加到h链表的尾部
ngx_queue_data(q, type, link)//取出包括q的type类型的地址。这样我们就能够訪问type内的成员
ngx_queue_t提供了14个经常使用的操作给用户使用,基本涵盖了插入、删除、移动。訪问数据等等操作,这14个函数都是宏定义。有兴趣的能够看下源代码。很easy。
这里说一个最后一个操作函数ngx_queue_data:
#define ngx_queue_data(q, type, link) \
(type *) ((u_char *) q - offsetof(type, link))
q为ngx_queue_t的指针, type是用户自己定义的包括ngx_queue_t的数据类型type。link是type的成员。类型是ngx_queue_t。
这里举个列子来说明这个操作的使用方法。
先看一个自己定义的结构体:
typedef struct
{
ngx_int_t num;
ngx_str_t str;
ngx_queue_t queue;
}TestNode;
假设我们有一个ngx_queue_t的指针q指向testNode.queue,如今我们不知到testNode的地址,仅仅知道queue,假设我们想訪问testNode里面的成员num,我们必须知道testNode的地址。这样才干訪问其num成员。如何知道testNode的地址呢?这时候ngx_queue_data就闪亮登场了。
我们能够用一下语句来取得testNode的地址:
TestNode* testnode = ngx_queue_data(q, TestNode, queue);
这样我们就能够訪问num了。
2.3 ngx_queue_middle
这个函数取出链表中间位置的节点。用一个慢指针midlle和一个快指针next,middle没走一步,next走两步,当next指针到达链表未的时候。midlle就指向链表的中间位置。
ngx_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每前进 一步,next都要前进两步。直到链表的尾部
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;
}
}
}
2.4 ngx_ngx_queue_sort
void
ngx_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);//q前面的元素必须是小于q
}
}
3 一个样例
#include <stdio.h>
#include <stdlib.h>
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_conf_file.h>
#include <nginx.h>
#include <ngx_queue.h> //////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//这两个东东必须写,不为有编译错误
volatile ngx_cycle_t *ngx_cycle; void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
const char *fmt, ...)
{
}
//////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////// typedef struct
{
ngx_int_t num;
ngx_str_t str;
ngx_queue_t queue;
}TestNode; ngx_int_t compare_node(const ngx_queue_t *left, const ngx_queue_t *right)
{
TestNode* left_node = ngx_queue_data(left, TestNode, queue);
TestNode* right_node = ngx_queue_data(right, TestNode, queue); return left_node->num > right_node->num;
} int main()
{
ngx_queue_t QueHead;
ngx_queue_init(&QueHead); TestNode Node[10];
ngx_int_t i;
for (i=0; i<10; ++i)
{
Node[i].num = rand()%100;
} ngx_queue_insert_head(&QueHead, &Node[0].queue);
ngx_queue_insert_tail(&QueHead, &Node[1].queue);
ngx_queue_insert_after(&QueHead, &Node[2].queue);
ngx_queue_insert_head(&QueHead, &Node[4].queue);
ngx_queue_insert_tail(&QueHead, &Node[3].queue);
ngx_queue_insert_head(&QueHead, &Node[5].queue);
ngx_queue_insert_tail(&QueHead, &Node[6].queue);
ngx_queue_insert_after(&QueHead, &Node[7].queue);
ngx_queue_insert_head(&QueHead, &Node[8].queue);
ngx_queue_insert_tail(&QueHead, &Node[9].queue); ngx_queue_t *q;
for (q = ngx_queue_head(&QueHead); q != ngx_queue_sentinel(&QueHead); q = ngx_queue_next(q))
{
TestNode* Node = ngx_queue_data(q, TestNode, queue);
printf("Num=%d\n", Node->num);
} ngx_queue_sort(&QueHead, compare_node); printf("\n");
for (q = ngx_queue_head(&QueHead); q != ngx_queue_sentinel(&QueHead); q = ngx_queue_next(q))
{
TestNode* Node = ngx_queue_data(q, TestNode, queue);
printf("Num=%d\n", Node->num);
} return 0;
}
nginx学习六 高级数据结构之双向链表ngx_queue_t的更多相关文章
- nginx 学习八 高级数据结构之基数树ngx_radix_tree_t
1 nginx的基数树简单介绍 基数树是一种二叉查找树,它具备二叉查找树的全部长处:检索.插入.删除节点速度快,支持范围查找.支持遍历等. 在nginx中仅geo模块使用了基数树. nginx的基数树 ...
- nginx学习七 高级数据结构之动态数组ngx_array_t
1 ngx_array_t结构 ngx_array_t是nginx内部使用的数组结构.nginx的数组结构在存储上与大家认知的C语言内置的数组有相似性.比方实际上存储数据的区域也是一大块连续的内存. ...
- nginx学习(六):日志切割
现有的日志都会存在 access.log 文件中,但是随着时间的推移,这个文件的内容会越来越多,体积会越来越大,不便于运维人员查看,所以我们可以通过把这个大的日志文件切割为多份不同的小文件作为日志,切 ...
- Nginx学习笔记(五):高级数据结构
目录 动态数组 单向链表 双端队列 红黑树 缓冲区 数据块链 键值对 动态数组 ngx_array_t 表示一块连续的内存,其中存放着数组元素,概念上和原始数组很接近 // 定义在 core/ng ...
- 菜鸟nginx源码剖析数据结构篇(二) 双向链表ngx_queue_t[转]
nginx源码剖析数据结构篇(二) 双向链表ngx_queue_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn. ...
- GO语言的进阶之路-Golang高级数据结构定义
GO语言的进阶之路-Golang高级数据结构定义 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们之前学习过Golang的基本数据类型,字符串和byte,以及rune也有所了解, ...
- Shell高级编程视频教程-跟着老男孩一步步学习Shell高级编程实战视频教程
Shell高级编程视频教程-跟着老男孩一步步学习Shell高级编程实战视频教程 教程简介: 本教程共71节,主要介绍了shell的相关知识教程,如shell编程需要的基础知识储备.shell脚本概念介 ...
- Nginx系列0:Nginx学习历程
Nginx学习历程 一.初识Nginx 1.Nginx适用于哪些场景 (1)静态资源服务 通过本地文件系统提供服务 (2)反向代理服务 Nginx的强大性能 缓存 负载均衡 (3)API服务 Open ...
- Nginx学习总结
2017年2月23日, 星期四 Nginx学习总结 Nginx是目前比较主流的HTTP反向代理服务器(其企业版提供了基于TCP层的反向代理插件),对于构建大型分布式web应用,具有举足轻重的作用.简单 ...
随机推荐
- 关于new Function使用以及将json格式字符串转化为json对象方法介绍
一直对Function()一知半解,今日就Function()的使用做一下总结 一.函数实际是功能完整的对象,用Fucntion()直接创建函数. 语法规则: var 函数名 = new Fun ...
- SAE上使用本地sql文件建表时出错解决方法
在SAE上部署网站时需要上传本地的数据库结构,我也导出了本地数据库为sql文件,但是上传到SAE上时遇到了如下错误: MySQL 返回: #1044 - Access denied for user ...
- codeforces 374D. Inna and Sequence 线段树
题目链接 给m个数, n个操作, 一个数列, 初始为空.一共有3种操作, 在数列末尾加0, 加1, 或删除位置为a[i]的数, a[i]为初始给的m个数, 如果a[i]大于数列长度, 那么什么也不发生 ...
- feof()和EOF的用法(转载)
查看 stdio.h 可以看到如下定义: #define EOF (-1) #define _IOEOF 0x0010 #define feof(_stream) ((_stream)-& ...
- LintCode-删除元素
题目描述: 给定一个数组和一个值,在原地删除与值相同的数字,返回新数组的长度. 元素的顺序可以改变,并且对新的数组不会有影响. 样例 给出一个数组 [0,4,4,0,0,2,4,4],和值 4 返回 ...
- Oracle SQL篇(三)Oracle ROWNUM 与TOP N分析
首先我们来看一下ROWNUM: 含义解释: 1.rownum是oracle为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推.这是一个伪列,可以用于限制查询返回的总行数. 2 ...
- UV印刷
UV就是在一张印上你想要的图案上面过上一层油,主要是增加产品亮度,保护产品表面,其硬度高,耐腐蚀摩擦,不易出现划痕等,有些复膜产品现改为上UV,能达到环保要求,但UV产品不易粘接,有些只能通过局部UV ...
- Protel99se轻松入门:一些高级设置和常用技巧
给PCB补泪滴的具体操作 这里我们可以知道给PCB做覆铜是多么的简单 在PCB中如何找到我们要找的封装 在PCB中如何打印出中空的焊盘(这个功能对于热转印制板比较有用) 如何在PCB文件中加上漂亮的汉 ...
- poj 1204 Word Puzzles(字典树)
题目链接:http://poj.org/problem?id=1204 思路分析:由于题目数据较弱,使用暴力搜索:对于所有查找的单词建立一棵字典树,在图中的每个坐标,往8个方向搜索查找即可: 需要注意 ...
- java项目组会议纪要
上周五项目经理开例会让我记录会议纪要,以下是我记录的纪要.给大家分享一下! 一.时间:2014年04月25日 二.地点:研发部 三.人物:xx,xx,xx 四.内容(相关项目的一些事项): 1.对待需 ...