ngx_rbtree_init
定义 在 src\core\ngx_rbtree.h
c
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;
};
#define ngx_rbtree_init(tree, s, i) \
ngx_rbtree_sentinel_init(s); \
(tree)->root = s; \
(tree)->sentinel = s; \
(tree)->insert = i
c
struct ngx_rbtree_s {
ngx_rbtree_node_t *root;
ngx_rbtree_node_t *sentinel;
ngx_rbtree_insert_pt insert;
};
1. ngx_rbtree_node_t *root
-
作用:指向红黑树的根节点。
-
根节点是红黑树的入口,所有操作(插入、查找、删除)都从根节点开始。
-
初始时,根节点指向哨兵节点(表示空树);当插入第一个数据节点后,根节点会指向该节点。
-
通过根节点动态管理树的结构变化(如旋转、颜色调整)。
-
根节点与哨兵节点的绑定(初始化时
root = sentinel
)简化了空树与非空树的逻辑统一性。
-
2. ngx_rbtree_node_t *sentinel
-
作用:指向红黑树的哨兵节点(Sentinel Node)。
-
哨兵节点是一个特殊的空节点,作为所有叶子节点和父节点的"占位符"。
-
所有节点的
left
、right
、parent
指针在未分配时均指向哨兵。 -
简化边界条件:避免空指针检查。例如,当遍历到叶子节点时,直接通过哨兵终止递归或循环。
-
统一操作逻辑:无论是空树还是非空树,插入/删除操作的代码路径一致,无需额外分支判断。
-
红黑树性质:哨兵节点颜色始终为黑色,确保红黑树性质(如根节点为黑色、叶子节点为黑色)。
-
3. ngx_rbtree_insert_pt insert
-
作用:指向红黑树的插入策略函数。
-
定义插入新节点时的键比较逻辑(如按数值大小、按时间戳排序)。
-
Nginx 提供了两种预定义策略:
ngx_rbtree_insert_value
:按节点键的数值排序(升序)。ngx_rbtree_insert_timer_value
:按时间戳排序(用于定时器管理)。
-
策略模式:通过函数指针注入不同的插入逻辑,使红黑树可复用于不同场景。
-
解耦逻辑:将红黑树的通用操作(如旋转、颜色调整)与业务逻辑(键比较)分离,提高代码复用性。
-
c
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;
};
1. ngx_rbtree_key_t key
-
作用:存储节点的键值,用于排序和查找。
-
键值是红黑树的排序依据,决定了节点在树中的位置。
-
通过键值快速定位节点
-
支持自定义键比较逻辑
-
2. ngx_rbtree_node_t *left
和 *right
- 作用 :指向左、右子节点的指针。
-
左子节点:键值小于当前节点(根据插入策略)。
-
右子节点:键值大于当前节点(根据插入策略)。
-
初始时,左右子节点均指向哨兵(表示空树)。
-
维护二叉搜索树的有序性(左小右大)。
-
支持快速遍历
-
3. ngx_rbtree_node_t *parent
- 作用 :指向父节点的指针。
-
记录当前节点的父节点位置,用于树的调整操作(如旋转、颜色翻转)。
-
根节点的父节点指向哨兵。
-
在插入/删除时,通过父节点链回溯调整树的平衡。
-
例如:插入新节点后,从该节点向上检查红黑树性质是否被破坏。
-
4. u_char color
-
作用 :标记节点颜色(
0
表示黑色,1
表示红色)。- 颜色标记是红黑树平衡的核心机制。
- 通过颜色调整和旋转操作,确保树的高度近似平衡(最坏情况下操作复杂度为 O(log n))。
5. u_char data
- 作用:存储附加数据(可选)。
- 意义 :
- Nginx 中通常不直接使用此字段,而是通过继承或封装扩展节点功能。
- 通过
data
字段实现节点与业务数据的关联,避免全局查找。 - 保持红黑树结构的通用性(键值和颜色是核心,业务数据通过
data
扩展)。
c
typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
1. 定义插入策略的回调函数
- 作用 :
该函数指针类型定义了红黑树插入操作的通用接口,用于指定如何将新节点插入到红黑树中。 - 意义 :
- 将红黑树的通用操作 (如平衡调整)与业务逻辑(如键值比较规则)分离。
- 允许用户自定义插入策略,适应不同场景(如按数值排序、按时间排序)。
2. 参数解析
ngx_rbtree_node_t *root
:
红黑树的根节点,插入操作从根节点开始遍历,找到新节点的合适位置。ngx_rbtree_node_t *node
:
待插入的新节点,其key
字段已初始化,用于决定插入位置。ngx_rbtree_node_t *sentinel
:
哨兵节点,用于标记空子节点和树的边界。
3. 典型插入策略示例
Nginx 内置了两种常用插入策略,通过函数指针动态绑定:
策略 1:按键值升序插入(ngx_rbtree_insert_value
)
- 逻辑 :
根据节点的key
字段从小到大排序,确保左子树键值 ≤ 父节点键值 ≤ 右子树键值。 - 应用场景 :
通用键值管理(如内存块大小索引)。
策略 2:按时间戳插入(ngx_rbtree_insert_timer_value
)
- 逻辑 :
根据节点的key
字段表示的时间戳排序,最近超时的事件位于最左侧。 - 应用场景 :
Nginx 定时器模块(管理 HTTP 超时、缓存过期等事件)。
设计思想
1. 策略模式(Strategy Pattern)
- 核心思想 :
将算法(插入逻辑)与数据结构(红黑树)解耦,通过函数指针动态切换策略。 - 优势 :
- 复用性:同一红黑树结构可服务于不同业务(如内存管理、定时器)。
- 可扩展性:用户可自定义插入逻辑(如按字符串、IP 地址排序),无需修改红黑树核心代码。
2. 分层设计
- 通用层 :
红黑树负责平衡操作(旋转、颜色调整),与键值无关。 - 业务层 :
插入策略函数实现具体的键值比较逻辑
c
#define ngx_rbtree_init(tree, s, i) \
ngx_rbtree_sentinel_init(s); \
(tree)->root = s; \
(tree)->sentinel = s; \
(tree)->insert = i
ngx_rbtree_init
是 Nginx 中用于初始化红黑树的宏
1. ngx_rbtree_sentinel_init(s);
- 作用 :初始化哨兵节点
s
。
ngx_rbtree_sentinel_init - 逻辑 :
红黑树使用哨兵节点(sentinel)作为所有叶子节点和根节点的"空"占位符。此行将哨兵节点s
的左右子节点、父节点均指向自身,并设置颜色为黑色(红黑树性质要求哨兵为黑色)。 - 意图 :
哨兵节点简化了边界条件处理(如空树或叶子节点的操作),避免频繁的空指针检查,提升代码效率和可维护性。
2. (tree)->root = s;
- 作用:将红黑树的根节点初始化为哨兵。
- 逻辑 :
初始时树为空,根节点指向哨兵,表示树中无有效数据节点。 - 意图 :
统一空树与非空树的处理逻辑。后续插入节点时,根节点会动态更新为实际节点,但始终通过哨兵节点维护树的结构完整性。
3. (tree)->sentinel = s;
- 作用 :将红黑树的哨兵指针指向
s
。 - 逻辑 :
红黑树结构体中需保存哨兵节点的引用,以便在插入、删除等操作中快速访问哨兵。 - 意图 :
确保所有操作(如旋转、颜色调整)能正确识别和操作哨兵节点,维持红黑树的平衡性质。
4. (tree)->insert = i;
- 作用 :设置红黑树的插入策略函数为
i
。 - 逻辑 :
i
是一个函数指针,指向具体的插入逻辑(如ngx_rbtree_insert_value
或自定义函数)。不同场景下,红黑树的键比较方式可能不同(如按时间、按字符串等),通过注入插入策略实现灵活性。 - 意图 :
支持多种插入策略,使红黑树可复用于不同场景(如定时器管理、缓存索引),提升代码复用性。