一、红黑树用途在哪里?
1 map–>
2 nginx–>
3 定时器–>
4 cfs (进程调度的集合 )(操作系统中用红黑树存储的集合)(查找速度快,有顺序)
5 内存管理(红黑树的平衡关系);
问题:典型的malloc的内存碎片?
解答:一块内存对应一个key;
key指向的内存的地址 加上长度就是对内存碎片的管理, key value -->查找。
问题:红黑树有什么应用呢?
1>大多数自平衡BST(self-balancing BST) 库函数都是用红黑树实现的,比如C++中的map 和 set (或者 Java 中的 TreeSet 和 TreeMap)。
2>红黑树也用于实现 Linux 操作系统的 CPU 调度。完全公平调度(Completely Fair Scheduler)使用的就是红黑树。
二、概念
1.每个结点是红的或者黑的
2 根结点是黑的
3 每个叶子结点是黑的(NULL)
4 树中不存在两个相邻的红色结点(即红色结点的父结点和孩子结点均不能是红色)
5 从任意一个结点(包括根结点)到其任何后代 NULL 结点(默认是黑色的)的每条路径都具有相同数量的黑色结点。
这就是一颗典型的红黑树,树中的每个结点的颜色要么是黑色,要么是红色;根结点 6 为黑色结点;树中不存在两个相邻的红色结点,比如结点 15 为红色结点,其父亲节点 6 与两个孩子结点就一定是黑色,而不能是红色;从结点到其后代的 NUll结点 的每条路径上具有相同数目的黑色结点,比如根结点 6 到其左子树的 NULL结点 包含三个黑色结点,到其右子树所有的 NULL 结点也包含三个黑色结点。 可能还不够清晰,为此我对上图做了修改为所有默认为黑色的 NULL 结点给了一个标记。
现在解释规则的第四条简直不能再清晰了!比如根结点 6 到 NULL结点 a 的路径 6→2→a 上的黑色结点为 3 个,从根结点 6 到结点 c 的路径 6→15→10→9→c 中包含的黑色结点个数也是 3 个,同理从根结点 6 到其他所有 NULL结点 的黑色结点数都是 3 。再举个栗子,从红色结点 15 到NULL结点 d 的路径 15→18→g 包含 2 个黑色结点,到NULL结点 c 的路径 15→10→9→c 也包含黑色结点 2 个,从结点 15 到其所有后代的 NULL结点的 黑色结点数目都是 2 。
###红黑树RBT与平衡二叉树AVL比较:
AVL 树比红黑树更加平衡,但AVL树在插入和删除的时候也会存在大量的旋转操作。所以当你的应用涉及到频繁的插入和删除操作,切记放弃AVL树,选择性能更好的红黑树;当然,如果你的应用中涉及的插入和删除操作并不频繁,而是查找操作相对更频繁,那么就优先选择 AVL 树进行实现。
###什么是一颗红黑树的黑高(Black Height)?
在一颗红黑树中,从某个结点 x 出发(不包含该结点)到达一个叶结点的任意一条简单路径上包含的黑色结点的数目称为 黑高 ,记为 bh(x) 。
譬如结点6对应的黑高 和结点15 对应的黑高 都是2;
6->2->null ;
15->10->9_null(9是红色结点不算入黑高计算种);
二、实现红黑树
*实现红黑树的一个结点
typedef int KET_TYPE //key的类型
typedef struct _rbtree_node{
unsinged char color;
struct _rbbtree_node *left;
struct _rbbtree_node *right;
struct _rbbtree_node *parent; //结点的父亲
KEY_TYPE key; //rbtree上的结点的key 对应隐藏的value
void *value;
}rbtree_node;
实现红黑树
typedef struct _rbtree{
rbtree_node *root;
//根据红黑树的性质----每个叶子结点是黑的
//做一个通用的叶子结点(*nil),把所有的叶子结点放入其中去判断是否为黑色;
rbtree_node *nil;
};
红黑树的旋转
实现红黑树的左旋
void _left_rotate(rbtree *T,rbtree_node *x){
rtree_node *y =x->right; // 前提条件 y是x的右子结点
x->right = y->left; //把x的右子结点指向 y的左子结点b
if(y->left != T->nil) {// 判断此时y的左子结点是否为空结点
y->left->parent = x; // b的parent 指向x
}
y->parent = x->parent;// 把y的父结点指向x的父结点
if(x->parent == T->nil){ //判断x的父结点3种情况 1根 2左 3右 情况来x的父结点指向y
T->root = y
}else if(x == x->parent->left){
x-parent->left = y; //2左
}else {
x->parent->right = y; //3右
}
y->left = x; // 此时y结点已经在x原来的父结点上 将y的左子 指向x
x->parent = y; // x的父结点指向y
}
实现红黑树的右旋
void _right_rotate(rbtree *T,rbtree_node *y){
rtree_node *x =y->left; // 前提条件 x是y的左子结点
y-left = x->right;
if(x->right != T->nil) {// 判断此时y的左子结点是否为空结点
x->right->parent = y; // b的parent 指向y
}
x->parent = y->parent;// 把x的父结点指向y的父结点
if(y->parent == T->nil){ //判断y的父结点3种情况 1根 2左 3右 情况来y的父结点指向x
T->root = x
}else if(y == y->parent->left){
y-parent->left = x; //2左
}else {
y->parent->right = x; //3右
}
x->right= y;
y->parent = x;
}
三、总结
以上就是今天所掌握的内容,本文仅仅简单介绍了红黑树的用途和实现操作,还有插入删除,着色旋转的问题等待学习。