【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;
}
运行结果
截图如下: