这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战
红黑树是一种具有红色和黑色链接的平衡查找树,同时满足:
- 红色节点向左倾斜
- 一个节点不可能有两个红色链接
- 整个树完全黑色平衡,即从根节点到所以叶子结点的路径上,黑色链接的个数都相同。
## 红黑树结构体
```c
// insert function pointer
typedef void (*rbtree_insert_p)(rbtree_t *root, rbtree_node_t *node);
struct rbtree_t_ {
rbtree_node_t *root; // the pointer of the root of the tree
rbtree_node_t *sentinel; // sentinel as black leaf node
rbtree_insert_p insert;
};
这里着重讲一下哨兵结点,哨兵 sentinel 便于处理红黑树代码中的边界条件,使用一个哨兵 来代表所有的 NIL:所有的叶结点和(根结点的父结点)。 这样的好处就是满足了红黑树的约束条件之一,所有的叶结点都是黑色的。 这样可以在满足红黑树的叶结点全黑约束下,同时更方便标识树的边缘。 不仅将所有的叶子结点都用一个哨兵结点代替,节省了空间开销,同时还节省了叶结点逐一染黑的麻烦。 这种用法可以在算法导论(其中的双向链表实现中也使用了哨兵结点来简化边界判断)和 nginx 的实现中看到。
接口设计
/* macros */
#define rbtree_is_empty(rbt) ((rbt)->root == (rbt)->sentinel);
#define rbtree_set_insert_func(rbt, func) (rbt)->insert = func
#define rbtree_red(node) ((node)->color = 1)
#define rbtree_black(node) ((node)->color = 0)
#define rbtree_is_red(node) ((node)->color)
#define rbtree_is_black(node) (!((node)->color))
// copy color of n2 to n1
#define rbtree_copy_color(n1, n2) (n1->color = n2->color)
// sentinel for black leaf node
#define rbtree_sentinel_init(node) rbtree_set_black(node)
#define rbtree_init_(tree, s, i) \
rbtree_sentinel_init(s); \
(tree)->root = s; \
(tree)->sentinel = s; \
(tree)->insert = i
// public methods
void rbtree_init(rbtree_t *tree, rbtree_node_t *s);
void rbtree_insert_value(rbtree_t *tree, rbtree_node_t *node);
void rbtree_insert(rbtree_t *tree, rbtree_node_t *node);
void rbtree_delete(rbtree_t *tree, rbtree_node_t *node);
/* get the minimum key of node in a subtree of the rbtree */
static inline rbtree_node_t *rbtree_subtree_min(rbtree_t *tree,
rbtree_node_t *node)
{
while (node->left != tree->sentinel) {
node = node->left;
}
return node;
}
//寻找以任意结点为根结点的子树中边缘的左子结点就是结点值最小的结点。