知识温习:
wiki-red-black tree insert node,对插入节点有详细的介绍
wiki-AVL-tree insert rotate, 对平衡二叉树旋转调整
前言
红黑树的5大“纪律”
性质1. 节点是红色或黑色。
性质2. 根是黑色。
性质3. 所有叶子都是黑色(叶子是NIL节点)。
性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
性质5. 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。
以上5条,是红黑树“铁”的纪律,任何一条不成立,就不再是一棵红黑树。而红黑树节点的插入会导致原有红黑树中的某些性质不再成立,因此需要对树进行适当的调整(旋转——附带性的改变孩子,改变父亲或者改变颜色)使之依旧是一棵红黑树。下文介绍的就是内核对红黑树插入节点的调整分析!如果对AVL树不了解,树的插入节点不了解,请查看我给予的wiki链接进行温习,否则,你可能会看不明白下文中操作的原因。
1、更换孩子节点
<linux/rbtree_augmented.h>
static inline void
__rb_change_child(struct rb_node *old, struct rb_node *new,
struct rb_node *parent, struct rb_root *root)
{
if (parent) {//parent不空,则不是树根
if (parent->rb_left == old)//更换是左孩子
parent->rb_left = new;
else //更换的是右孩子
parent->rb_right = new;
} else //更换树根
root->rb_node = new;
}
内部函数——只有单一功能实现,不做安全机制,以及高级功能封装,核心一向如此。
2、旋转辅助函数
<lib/rbtree.c>
__rb_rotate_set_parents(struct rb_node *old, struct rb_node *new, struct rb_root *root, int color)
{
//获取old的父节点
struct rb_node *parent = rb_parent(old);
//old's parent and color get assigned to new
new->__rb_parent_color = old->__rb_parent_color;
//old gets assigned new as a parent and 'color' as a color
rb_set_parent_color(old, new, color);
//把parent的old孩子替换成new
__rb_change_child(old, new, parent, root);
}
3、"插入"节点
<lib/rbtree.c>
void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
__rb_insert(node, root, dummy_rotate);
}
EXPORT_SYMBOL(rb_insert_color);
很显然,这是对外导出使用的外部函数,真正的功能函数是__rb_insert();
一般刚看到代码时候,会觉得困惑,为什么函数名字叫rb_insert_color(),而不是rb_insert_node之类的?
原因在上一篇博客中“核心对红黑树使用两点说明