《深入理解Nginx 模块开发与架构解析》之高级数据结构摘录

一、ngx_queue_t双向链表

  1.ngx_queue_t容器的优势在于:

     1) 实现了排序功能;

     2) 它非常轻量级,是一个纯粹的双向链表。它不负责链表元素所占内存的分配,与Nginx封装的ngx_pool_t内存池完全无关。

     3) 支持两个链表间的合并。

typedef struct ngx_queue_s ngx_queue_t;

struct ngx_queue_s {
    ngx_queue_t *prev;
    ngx_queue_t *next;
};

  2.ngx_queue_t容器提供的操作方式

     

   3.ngx_queue_t双向链表容器所支持的方法

方法名 参数含义 执行意义
ngx_queue_init(h) h为链表容器结构体ngx_queue_t的指针 将链表容器h初始化,这时会自动置为空链表
ngx_queue_empty(h) h为链表容器结构体ngx_queue_t的指针 检测链表容器中是否为空,即是否没有一个元素存在。如果返回非0,表示链表h是空的。
ngx_queue_insert_head(h, x) h为链表容器结构体ngx_queue_t的指针,x为插入元素结构体中ngx_queue_t成员的指针 将元素x插入到链表容器h的头部
ngx_queue_insert_tail(h, x) h为链表容器结构体ngx_queue_t的指针,x为插入元素结构体中ngx_queue_t成员的指针

将元素x添加到链表容器h的末尾

ngx_queue_head(h) h为链表容器结构体ngx_queue_t的指针 返回链表容器h中的第一个元素的ngx_queue_t结构体指针
ngx_queue_last(h) h为链表容器结构体ngx_queue_t的指针 返回链表容器中的最后一个元素的ngx_queue_t结构体指针
ngx_queue_sentinel(h) h为链表容器结构体ngx_queue_t的指针 返回链表容器结构体的指针
ngx_queue_remove(x) x为插入元素结构体中ngx_queue_t成员的指针 由容器中移除x元素
ngx_queue_split(h, q,n) h为链表容器结构体ngx_queue_t的指针 ngx_queue_split用于拆分链表,h是链表容器,而q是链表h中的一个元素。这个方法将链表h以元素q为界拆分成两个链表h和n,其中h由原链表的前半部分构成(不包括q),而n由原链表的后半部分构成,q是它的首元素。
ngx_queue_add(h, n) h为链表容器结构体ngx_queue_t的指针,n为另一个链表容器结构体ngx_queue_t的指针 合并链表,将n链表添加到h链表的末尾
ngx_queue_middle(h) h为链表容器结构体ngx_queue_t的指针 返回链表中心元素,如,链表共有N个元素,ng_queue_middle方法将返回第N/2+1个元素,例如,链表有4个元素,将会返回第3个元素(不是第2个元素)
ngx_queue_sort(h, cmpfunc) h为链表容器结构体ngx_queue_t的指针,cmpfunc是两个链表元素的比较方法,如果它返回正数,则表示以升序排序 使用插入排序法对链表进行排序,cmpfunc需要使用者自己实现,它的原型是这样的:ngx_int_t (*cmpfunc)(const ngx_queue_t *, const ngx_queue_t *)

   4.  ngx_queue_t双向链表中的元素所支持的方法

方法名 参数含义 执行意义
ngx_queue_next(q) q为链表中某一个元素结构体的ngx_queue_t成员的指针 返回q元素的下一个元素
ngx_queue_prev(q) q为链表中某一个元素结构体的ngx_queue_t成员的指针 返回q元素的上一个元素
ngx_queue_data(q, type, link) q为链表中某一个元素结构体的ngx_queue_t成员的指针,type为链表元素的结构体类型名称(该结构体中必须包含ngx_queue_t类型的成员),lin开始上面这个结构体中ngx_queue_t类型的成员名字 返回q元素(ngx_queue_t类型)所属结构体(任何struct类型,其中可在任意位置包含ngx_queue_t类型的成员)的地址
ngx_queue_insert_after(q, x) q为链表中某个元素结构体的ngx_queue_t成员的指针,x为插入元素结构体中ngx_queue_t成员的指针 将元素x插入到元素q之后

   5.空容器时ngx_queue_t结构体成员的值

      

    6.当仅含1个元素时,容器、元素中的ngx_queue_t结构体成员的值

    

   7.当含有两个或多个元素时,容器、元素中的ngx_queue_t结构体中prev、next成员的值

    

二、ngx_array_t动态数组

    ngx_array_t是一个顺序容器,它在Nginx中大量使用。ngx_array_t容器以数组的形式存储元素,并支持在达到数组容量的上限时动态改变数组的大小。

     优点:

      1)访问速度快

       2)允许元素个数具备不确定性;

       3)负责元素占用内存的分配,这些内存将由内存池统一管理。

    1.ngx_array_t动态数组的实现仅使用1个结构体,如下:

typedef struct ngx_array_s ngx_array_t;
struct ngx_array_s {
    //elts指向数组的首地址
    void *elts;
    //nelts是数组中已经使用的元素个数
    ngx_uint_t nelts;
    //每个数组元素占用的内存大小
    size_t size;
    //当前数组中能够容纳元素个数的总大小
    ngx_uint_t nalloc;
    //内存池对象
    ngx_pool_t *pool;
};

     2.ngx_array_t动态数组结构体中的成员及其提供的方法

       

     3.ngx_array_t动态数组提供的方法

        

三、ngx_list_t单向链表

     相当于动态数组与单向链表的结合体。

四、ngx_rbtree_t红黑树

    ngx_rbtree_t是使用红黑树实现的一种关联容器,Nginx的核心模块(如定时器管理、文件缓存模块等)在需要快速检索、查找的场合下都使用了ngx_rbtree_t容器。

    顺序容器的检索效率通常情况下都比较差,一般只能遍历检索指定元素。当需要容器的检索速度很快,或者需要支持范围查询时,ngx_rbtree_t红黑树容器是一个非常好的选择。

    什么是自平衡二叉查找树?在不断地向二叉查找树中添加、删除节点时,二叉查找树自身通过形态的变换,始终保持着一定程度上的平衡,即为自平衡二叉查找树。自平衡二叉查找树有许多种不同的实现方式,如AVL树和红黑树。红黑树是一种自平衡性较好的二叉查找树,它在Linux内核、C++的STL库等许多场合下都作为核心数据结构使用。

    ngx_rbtree_t红黑树容器中的元素都是有序的,它支持快速的检索、插入、删除操作,也支持范围查询、遍历等操作,是一种应用场景非常广泛的高级数据结构。

    红黑树是指每个节点都带有颜色属性的二叉查找树,其中颜色为红色或黑色。除了二叉查找树的一般要求以外,对于红黑树还有如下的额外的特性。

     特性1:节点时红色或黑色。

     特性2:根节点是黑色。

     特性3:所有叶子节点都是黑色(叶子是NIL节点,也叫“哨兵”)。

     特性4:每个红色节点的两个子节点都是黑色(每个叶子节点到根节点的所有路径上不能有两个连续的红色节点)>

     特性5:从任一节点到其每个叶子节点的所有简单路径都包含相同数目的黑色节点。

  1.ngx_rbtree_t红黑树的典型图示

      

   2.红黑树节点的结构体及其提供的方法

     

    3.ngx_rbtree_node_t结构体的定义

typedef struct ngx_rbtree_s ngx_rbtree_t;

/*为解决不同节点含有相同关键字的元素冲突问题,红黑树设置了ngx_rbtree_insert_pt指针,这样可灵活地添加冲突元素 */
typedef void (*ngx_rbtree_insert_pt)(ngx_rbtree_node_t *root,
    ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);

struct ngx_rbtree_s {
    //指向树的根节点。注意,根节点也是数据元素
    ngx_rbtree_node_t *root;
    //指向NIL哨兵节点
    ngx_rbtree_node_t *sentinel;
    //表示红黑树添加元素的函数指针,它决定在添加新节点时的行为究竟是替换还是新增
    ngx_rbtree_insert_pt insert;
};

      ngx_rbtree_t结构体的root成员指向根节点,而sentinel成员指向哨兵节点。

      4.Nginx为红黑树已经实现好的3种数据添加方法

        

        

         

    5.ngx_str_rbtree_insert_value的实现

       

五、ngx_radix_tree_t基数树

   详见资料

六、支持通配符的散列表

  6.1 ngx_hash_t基本散列表

    详见资料

  6.2 支持通配符的散列表

    详见资料

猜你喜欢

转载自blog.csdn.net/zhangge3663/article/details/83180659