【nginx源码学习与运用 六】红黑树结构ngx_rbtree_t

【nginx源码学习与运用】系列博客中的示例代码在csdn的代码托管服务器CODE上,地址https://code.csdn.net/u012819339/nginx_study ,你可以将其自由的下载到本地,或者通过Git来实时获取更新


红黑树的原理就不在赘述了,这里着重给个例子,说明一下怎么运用nginx中的这个结构。

相关结构

struct ngx_rbtree_node_s {
    ngx_rbtree_key_t       key; //关键字
    ngx_rbtree_node_t     *left; //左子节点
    ngx_rbtree_node_t     *right; //右子节点
    ngx_rbtree_node_t     *parent; //父节点
    u_char                 color; //节点颜色 0:黑色  1:红色
    u_char                 data; //节点数据,很少用
};

//为解决不同节点含有相同关节自的元素冲突问题,红黑树设置了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; //指向树的根节点
    ngx_rbtree_node_t     *sentinel; //哨兵节点
    ngx_rbtree_insert_pt   insert; //添加元素的函数指针
};

结构图

红黑树的结构都是一样的,nginx中的红黑树结构没有什么特别的地方
这里写图片描述

操作方法

nginx为红黑树已经实现好的数据添加方法

函数 解释
ngx_rbtree_insert_value 向红黑树添加数据节点,每个数据节点的关键字都是唯一的,不存在同一个关键字有多个节点的问题
ngx_rbtree_insert_timer_value 向红黑树中添加数据节点,每个数据节点的关键字表示时间或者时间差
ngx_str_rbtree_insert_value 该函数在ngx_string.h中声明。向红黑树中添加数据节点,每个数据节点的关键字可以不是唯一的,但它们是以字符串作为唯一标识,存放在ngx_str_node_t结构体的str成员中

红黑树容器提供的方法

函数 解释
ngx_rbtree_init 初始化红黑树,包括初始化根节点、哨兵节点、ngx_rbtree_insert_pt节点添加方法
ngx_rbtree_insert 想红黑树中添加节点,该方法会通过旋转红黑树保持树的平衡
ngx_rbtree_delete 从红黑树中删除节点,该方法会通过旋转红黑树保持树的平衡

红黑树节点提供的方法

函数 解释
ngx_rbt_red 设置节点颜色为红色
ngx_rbt_black 设置节点颜色为黑色
ngx_rbt_is_red 判断节点是否为红,是则返回ture,否则返回false
ngx_rbt_is_black 判断节点是否为黑
ngx_rbt_copy_color 将n2节点颜色复制到n1节点
ngx_rbtree_min 找到当前节点及其子树中的最小节点(按照key关键字)
ngx_rbtree_sentinel_init 初始化哨兵节点

示例代码

arvik将nginx中的部分基础结构代码提出来了,好作为新手学习练习使用。见 https://code.csdn.net/u012819339/nginx_study
main.c

/*
blog:   http://blog.csdn.net/u012819339
email:  [email protected]
author: arvik
*/

#include <stdio.h>
#include <string.h>
#include "ak_core.h"
#include "pt.h"

typedef struct _testrbn
{
    ngx_rbtree_node_t node;
    ngx_uint_t num;
}TestRBTreeNode;

int main()
{
    ngx_rbtree_t rbtree;
    ngx_rbtree_node_t sentinel;
    int i=0;

    ngx_rbtree_init(&rbtree, &sentinel, ngx_rbtree_insert_value);

    TestRBTreeNode rbn[10];
    rbn[0].num = 1;
    rbn[1].num = 6;
    rbn[2].num = 8;
    rbn[3].num = 11;
    rbn[4].num = 13;
    rbn[5].num = 15;
    rbn[6].num = 17;
    rbn[7].num = 22;
    rbn[8].num = 25;
    rbn[9].num = 27;

    for(i=0; i<10; i++)
    {
        rbn[i].node.key = rbn[i].num;
        ngx_rbtree_insert(&rbtree, &rbn[i].node);
    }
    //此时,红黑树的形态就如博客中的结构图一样

    //查找红黑树中最小节点
    ngx_rbtree_node_t *tmpnode = ngx_rbtree_min(rbtree.root, &sentinel);
    PT_Info("the min key node num val:%u\n", ((TestRBTreeNode *)(tmpnode))->num );

    //演示怎么查找key为13的节点
    ngx_uint_t lookupkey = 13;
    tmpnode = rbtree.root;
    TestRBTreeNode *lknode;
    while(tmpnode != &sentinel )
    {
        if(lookupkey != tmpnode->key)
        {
            tmpnode = (lookupkey < tmpnode->key)?tmpnode->left:tmpnode->right;
            continue;
        }
        lknode = (TestRBTreeNode *)tmpnode; //这里强制转换类型,需要ngx_rbtree_node_t是TestRBTreeNode的第一个成员,也可以用类似于linux内核中的宏定义container_of获取自定义结构体地址
        break;
    }
    PT_Info("fine key == 13 node, TestRBTreeNode.num:%d\n", lknode->num);

    //删除num为13的节点
    ngx_rbtree_delete(&rbtree, &lknode->node);
    PT_Info("delete the node which num is equal to 13 complete!\n");

    return 0;
}

运行结果

截图如下:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/u012819339/article/details/53523114