1 定义
ngx_rbtree_next 函数 定义在 ./nginx-1.24.0/src/core/ngx_rbtree.c
ngx_rbtree_node_t*ngx_rbtree_next(ngx_rbtree_t*tree,ngx_rbtree_node_t*node){ngx_rbtree_node_t*root,*sentinel,*parent;sentinel=tree->sentinel;if(node->right!=sentinel){returnngx_rbtree_min(node->right,sentinel);}root=tree->root;for(;;){parent=node->parent;if(node==root){returnNULL;}if(node==parent->left){returnparent;}node=parent;}}
`ngx_rbtree_next` 函数的作用是: 返回红黑树中给定节点的中序遍历后继节点。 若该节点已是树中最大节点(无后继),则返回 `NULL`。
2 详解
1 函数签名
ngx_rbtree_node_t*ngx_rbtree_next(ngx_rbtree_t*tree,ngx_rbtree_node_t*node)
函数返回 后继节点的指针
参数1 ngx_rbtree_t *tree 指向要查找的红黑树 参数2 ngx_rbtree_node_t *node 指向要查找的当前节点指针 node
2 逻辑流程
1 局部变量 2 右子树 3 向上回溯
1 局部变量
{ngx_rbtree_node_t*root,*sentinel,*parent;sentinel=tree->sentinel;
声明三个局部指针变量: root:将用于保存树的根节点。 sentinel:将用于保存树的哨兵节点(NIL 节点)。 parent:在循环中暂存当前节点的父节点。
2 右子树
if(node->right!=sentinel){returnngx_rbtree_min(node->right,sentinel);}
判断当前节点 node 的右孩子是否非空(即不等于哨兵)。 如果右子树存在,根据二叉搜索树中序后继的定义: 后继就是右子树中的最小节点。 调用 ngx_rbtree_min(node->right, sentinel),从右子树的根出发,一路向左走到底, 返回最左下的节点(即右子树的最小节点),然后直接返回该节点。
3 向上回溯
root=tree->root;
保存树的根节点指针,用于后续循环的终止判断。 当右子树为空时,需要向上回溯寻找“最低的、使得当前节点位于其左子树中”的祖先节点, 而根节点是回溯的上界。
for(;;){parent=node->parent;if(node==root){returnNULL;}if(node==parent->left){returnparent;}node=parent;}}
#1 进入无限循环,用于向上遍历父节点链,直到找到后继或确认无后继。 #2 获取当前节点 node 的父节点,存入 parent。 Nginx 的红黑树节点结构里有一个 parent 指针, 根节点的父节点指向 sentinel, 但我们在访问 parent 前会先处理根节点的情况。 #3 如果当前节点恰好是整棵树的根节点 此时后继不存在,返回 NULL 表示已经到达末尾。 #4 如果当前节点是它父节点的左孩子,说明父节点就是比 node 大的最小节点,即中序后继。 直接返回该父节点,结束查找。 #5 如果不满足以上条件(即 node 是父节点的右孩子), 则说明父节点小于当前节点,需要继续向上回溯。 将 node 更新为父节点,进入下一次循环,继续检查它的父节点。