Nginx源码解析 --红黑树

news2025/7/10 12:29:07

预读知识

红黑树是一种自平衡二叉树,不仅可以使用二分法快速查找,而且插入和删除操作的效率也很高,常用于构造关联数组(例如C++标准库里的set和 map)。

在Nginx里红黑树主要用在事件机制里的定时器,检查连接超时,此外还在reslover、cache里用于快速查找。

 红黑树概要_编程界的谢菲尔德的博客-CSDN博客

  1. 节点不是黑色,就是红色(非黑即红)
  2. 根节点为黑色
  3. 叶节点为黑色(叶节点是指末梢的空节点 NilNull
  4. 一个节点为红色,则其两个子节点必须是黑色的(根到叶子的所有路径,不可能存在两个连续的红色节点)
  5. 每个节点到叶子节点的所有路径,都包含相同数目的黑色节点(相同的黑色高度)

基本数据结构

typedef ngx_uint_t  ngx_rbtree_key_t;
typedef ngx_int_t   ngx_rbtree_key_int_t;


typedef struct ngx_rbtree_node_s  ngx_rbtree_node_t;

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;
    u_char                 data;
};


typedef struct ngx_rbtree_s  ngx_rbtree_t;

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;
};

结构定义

1.

typedef ngx_uint_t  ngx_rbtree_key_t;                 //无符号
typedef ngx_int_t   ngx_rbtree_key_int_t;           //有符号

2结点                                           //侵入容器

ngx_rbtree_key_t         key;       //红黑树的键 用于排序比较

 ngx_rbtree_node_t     *left;      //左指针
 ngx_rbtree_node_t     *right;    //右指针
 ngx_rbtree_node_t     *parent; //父结点
 u_char                          color;    // 1代表 0代表 黑色
 u_char                          data;     // 无意义

3 树                                            

 ngx_rbtree_node_t     *root;           //红黑树的根节点:           
 ngx_rbtree_node_t     *sentinel;     //红黑树的哨兵节点,用于简化实现,它总是黑色的;
 ngx_rbtree_insert_pt   insert;         //节点的插入方法,允许对特殊节点定制特殊插入方法

4. 内存布局

 

2.操作函数

1.初始化(红为一  黑为0 同时也代表 正负)


#define ngx_rbt_red(node)               ((node)->color = 1)
#define ngx_rbt_black(node)             ((node)->color = 0)
#define ngx_rbt_is_red(node)            ((node)->color)
#define ngx_rbt_is_black(node)          (!ngx_rbt_is_red(node))
#define ngx_rbt_copy_color(n1, n2)      (n1->color = n2->color)


#define ngx_rbtree_sentinel_init(node)  ngx_rbt_black(node)
 

#define ngx_rbtree_init(tree, s, i)                                           \
    ngx_rbtree_sentinel_init(s);                                              \
    (tree)->root = s;                                                         \
    (tree)->sentinel = s;                                                     \
    (tree)->insert = i
ngx_rbtree_init实际上是一个宏,初始化后红黑树里仅有一个哨兵节点s,它同时也是根节点。

2.辅助函数 (旋转函数)(个人建议 直接看红黑树概要_编程界的谢菲尔德的博客-CSDN博客

1.左旋

static ngx_inline void
ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
    ngx_rbtree_node_t *node)
{
    ngx_rbtree_node_t  *temp;

    temp = node->right;
    node->right = temp->left;

    if (temp->left != sentinel) {
        temp->left->parent = node;
    }

    temp->parent = node->parent;

    if (node == *root) {
        *root = temp;

    } else if (node == node->parent->left) {
        node->parent->left = temp;

    } else {
        node->parent->right = temp;
    }

    temp->left = node;
    node->parent = temp;
}

2.右旋

static ngx_inline void
ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
    ngx_rbtree_node_t *node)
{
    ngx_rbtree_node_t  *temp;

    temp = node->left;
    node->left = temp->right;

    if (temp->right != sentinel) {
        temp->right->parent = node;
    }

    temp->parent = node->parent;

    if (node == *root) {
        *root = temp;

    } else if (node == node->parent->right) {
        node->parent->right = temp;

    } else {
        node->parent->left = temp;
    }

    temp->right = node;
    node->parent = temp;
}

3.删除

void
ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
{
    ngx_uint_t           red;
    ngx_rbtree_node_t  **root, *sentinel, *subst, *temp, *w;

    /* a binary tree delete */

    root = &tree->root;
    sentinel = tree->sentinel;

    if (node->left == sentinel) {
        temp = node->right;
        subst = node;

    } else if (node->right == sentinel) {
        temp = node->left;
        subst = node;

    } else {
        subst = ngx_rbtree_min(node->right, sentinel);

        if (subst->left != sentinel) {
            temp = subst->left;
        } else {
            temp = subst->right;
        }
    }
if (subst == *root) {
        *root = temp;
        ngx_rbt_black(temp);

        /* DEBUG stuff */
        node->left = NULL;
        node->right = NULL;
        node->parent = NULL;
        node->key = 0;

        return;
    }

    red = ngx_rbt_is_red(subst);

    if (subst == subst->parent->left) {
        subst->parent->left = temp;

    } else {
        subst->parent->right = temp;
    }

    if (subst == node) {

        temp->parent = subst->parent;

    } else {

        if (subst->parent == node) {
            temp->parent = subst;

        } else {
            temp->parent = subst->parent;
        }
  subst->left = node->left;
        subst->right = node->right;
        subst->parent = node->parent;
        ngx_rbt_copy_color(subst, node);

        if (node == *root) {
            *root = subst;

        } else {
            if (node == node->parent->left) {
                node->parent->left = subst;
            } else {
                node->parent->right = subst;
            }
        }

        if (subst->left != sentinel) {
            subst->left->parent = subst;
        }

        if (subst->right != sentinel) {
            subst->right->parent = subst;
        }
    }

    /* DEBUG stuff */
    node->left = NULL;
    node->right = NULL;
node->parent = NULL;
    node->key = 0;

    if (red) {
        return;
    }

    /* a delete fixup */

    while (temp != *root && ngx_rbt_is_black(temp)) {

        if (temp == temp->parent->left) {
            w = temp->parent->right;

            if (ngx_rbt_is_red(w)) {
                ngx_rbt_black(w);
                ngx_rbt_red(temp->parent);
                ngx_rbtree_left_rotate(root, sentinel, temp->parent);
                w = temp->parent->right;
            }

            if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
                ngx_rbt_red(w);
                temp = temp->parent;

            } else {
                if (ngx_rbt_is_black(w->right)) {
                    ngx_rbt_black(w->left);
                    ngx_rbt_red(w);
                    ngx_rbtree_right_rotate(root, sentinel, w);
                    w = temp->parent->right;
                }
.....
                                                  


                                        

4.插入

1.首先包装一个整的

ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)

2.分类

2.1void  ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
    ngx_rbtree_node_t *sentinel)    //这个是一个数值插入

2.2 void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
    ngx_rbtree_node_t *sentinel)    定时器红黑树的专用插入函数,键值是毫秒值

2.3 (字符串头文件里)

void ngx str_rbtree_insert_value ngx_rbtree_node_t *temp ,

ngx_rbtree_node_t *node , ngx_rbtree_node_t *sentinel);
//字符串红黑树的专用插入函数,键值是字符串的hash值



 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/38570.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Debian11之基于kubeadm安装K8S集群

官方安装教程 硬件要求 每台机器的内存要 2GB、CPU2 核心及以上 集群中的所有机器的网络彼此均能相互连接(公网和内网都可以) 节点之中不可以有重复的主机名、MAC 地址或 product_uuid 开启机器上的某些端口 为了保证 kubelet 正常工作,必须…

FluentCRM 2.6.0:更多功能、集成改进等等!

FluentCRM 2.6.0最新版发布了,它是一个主要的更新版本,为您带来了更多的功能、改进的集成、升级和错误修复!让我们来看看 FluentCRM 2.6.0 提供了什么新功能! 目录 FluentCRM 2.6的更高级过滤条件 电子邮件活动条件 基于自动化…

STC32G 单片机EEPROM 操作实例

一 STC32G 单片机EEPROM简介 STC32G系列单片机内部集成了大量的EEPROM,特别是STC32G12K128集成多达128K EEPROM。 STC32G内部EEPROM可擦写10万次,分若干扇区,每个扇区512字节。EEPROM的写操作只能将1写为0。要将0写为1,必须擦除…

Hive之函数

Hive之函数 第九章 函数 9.1 系统内置函数 9.1.1 理论 查看内置函数: show functions; 显示函数的详细信息: desc function abs; 显示函数的扩展信息: desc function extended concat; 一、关系运算: 1. 等值比较: 2. 等值…

VSCode:使用CMakeLists.txt构建C++项目

vscode配置 插件: CMake插件主要功能是CMake语法高亮、自动补全CMake Tools的功能主要是结合VSCode IDE使用CMake这个工具,比如生成CMake项目、构建CMake项目等CMake Tools Helper CMake工具本身还是要下载到本地,并且配置环境变量。 项目…

足球二三事 - 世界杯征文

征文活动链接: https://bbs.csdn.net/topics/609601920 从报纸上时候看 1982 年的世界杯,当时我们家里没有电视,晚上的时候听到马路对面的房子里传来惊呼声,也不知道为啥。 1983 年的春节前,家里要打扫房间&#xff…

UE4,UE5虚幻引擎源码版下载

1、进入Epic的GitHub仓库 https://github.com/EpicGames/Signup GitHub - EpicGames/Signup: Information about signing up for a free Epic Games account, and getting access to UnrealEngine source code. 2、加入EpicTeamAdmin 3、进入UnrealEngine仓库 4、找到需要下…

Linux系统中curl命令用法详解

在Linux系统中curl是一个利用URL规则在命令行下工作的文件传输工具,是一款强大的http命令行工具。它支持文件的上传和下载,是综合传输工具。 curl 是常用的命令行工具,用来请求 Web 服务器。它的名字就是客户端(client&#xff09…

(C语言)printf打印的字符串太长了,我想分两行!

本文来自于公众号&#xff1a;C语言编程技术分享 一、提问 有下述C程序&#xff1a; #include <stdio.h> #include <stdlib.h>int main() { printf("123456789012345678901234567890\n");system("pause");return 0; } printf函数要打印的字…

tomcat启动配置java_home,启动网址等,点击startup.bat直接启动

自己开发了一个网址&#xff08;基于angular&#xff09;&#xff0c;想共享给别人&#xff0c;直接点击运行&#xff0c;通过tomcat部署网站方式执行。 1、下载tomcat 从官网上下载tomcat&#xff0c;我下载的是tomcat9.0.36,下载完成后&#xff0c;解压&#xff1a; 双击b…

新知实验室

TUIRoom 是一个包含 UI 的开源音视频组件&#xff0c;通过集成 TUIRoom&#xff0c;可以在业务中快速上线音视频房间&#xff0c;屏幕分享&#xff0c;聊天等功能。 项目是开源的项目&#xff0c;根据自己 的需求设计项目。 创建步骤如下 &#xff1a; 一、 开通腾讯云实时…

被裁后一个offer都没有,测试人的问题出在哪里?

裁员潮涌&#xff0c;经济严冬。最近很多测试人过得并不好&#xff0c;行业缩水对测试岗位影响很直接干脆&#xff0c;究其原因还是测试门槛在IT行业较低&#xff0c;同质化测试人员比较多。但实际上成为一位好测试却有着较高的门槛&#xff0c;一名优秀的测试应当对产品的深层…

代码随想录65——额外题目【二叉树】:129求根节点到叶节点数字之和、1382将二叉搜索树变平衡、100相同的树、116填充每个节点的下一个右侧节点指针

文章目录1.129求根节点到叶节点数字之和1.1.题目1.2.解答2.1382将二叉搜索树变平衡2.1.题目2.2.解答3.100相同的树3.1.题目3.2.解答4.116填充每个节点的下一个右侧节点指针4.1.题目4.2.解答4.2.1.递归解法4.2.2.迭代方法1.129求根节点到叶节点数字之和 参考&#xff1a;代码随…

品优购项目详细分析

能够独立完成品优购首页制作哦 能够独立完成品优购列表页制作 能够独立完成品优购注册页制作 能够把品优购网站部署上线 网站制作流程&#xff1a; 初稿审核&#xff1a;网页美工会制作原型图和psd效果图 品优购项目规划&#xff1a; 1 品优购项目整体介绍 描述&#xff1…

【TS】函数重载--可选参数--默认参数

可选参数–默认参数 在ts中定义的数据类型&#xff0c;某些情况下只需要传入定义数据类型的一部分参数&#xff0c;比如&#xff1a;id 、name、age、address&#xff0c;此时需要修改用户的名称&#xff0c;那么只需要传入id、name就够了&#xff1b;某些情况下需要修改用户的…

.net-----集合和数据结构

集合和数据结构前言集合和数据结构的基本概念命名空间列表类集合列表类集合&#xff1a;数组列表列表类集合&#xff1a;列表List<T>双向链表LinkedList<T>字典类集合字典类集合类型哈希表Hashtable字典类集合&#xff1a;Dictionary<TKey, TValue >排序列表…

Vue3 Pinia 全局状态管理工具的使用

Pinia 是 Vue3 官方更推荐使用的全局状态管理工具。 Pinia 最初正是为了探索 Vuex 的下一个版本而开发的&#xff0c;因此整合了核心团队关于 Vuex 5 的许多想法。最终&#xff0c;我们意识到 Pinia 已经实现了我们想要在 Vuex 5 中提供的大部分内容&#xff0c;因此决定将其作…

E-梅莉的市场经济学

E-梅莉的市场经济学 题目背景 梅莉这个学期选修了经济学。但是主修心理学的她实在不擅长经济领域的分析&#xff0c;为此她时常抱怨自己学不会&#xff0c;想退课。 但是如果现在退掉的话这学期的学分就不够啦&#xff0c;因此她根据“梦中”的经历&#xff0c;“胡诌”了一…

Unity 如何实现框选游戏战斗单位

文章目录&#x1f354; Preface✨ 如何在屏幕坐标系内绘制框选框&#x1f389; 根据框选范围定位其在世界坐标系中对应的区域&#x1f947; 在该区域内进行物理检测&#x1f354; Preface 本文简单介绍如何实现即时战略游戏中框选战斗单位的功能&#xff0c;如图所示&#xff…

NeRF-SLAM 学习笔记

NeRF-SLAM: Real-Time Dense Monocular SLAM with Neural Radiance Fields 主页&#xff1a;https://deepai.org/publication/nerf-slam-real-time-dense-monocular-slam-with-neural-radiance-fields 论文&#xff1a;https://arxiv.org/pdf/2210.13641.pdf Code&#xff1a;…