目录
红黑树(red-black-tree)
一.红黑树的定义和性质
红黑树是一种二叉查找树,在每个结点上增加一个存储位表示结点的颜色,,可以是red或者是black。通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树保证没有一条路径会比其他路径长出两倍,因而是接近平衡的。可以证明,一颗有n个点内结点的红黑树的高度至多为2lg(n+1).
一颗红黑树应满足以下性质:
1.每个结点是红的或者是黑的
2.根结点是黑的
3.每个叶结点(NIL)是黑的
4.如果一个结点是红的,则它的两个儿子都是黑的
5.对于每个结点,从该结点到其他子孙结点的所有路径上包含相同数目的黑结点
(省略叶节点NIL)
二.红黑树的结构
树中的每个结点包括color,key,left,right,fa,分别表示结点的颜色,值,左儿子,右儿子,父结点。如果某结点没有一个子结点或者父结点,则该结点的相应指针指向NULL,这里定义一个哨兵表示NULL.
struct RB_Node{ //树结点
int key;
bool color;
RB_Node *fa, *left, *right;
};
struct RB_tree{ //红黑树(red-black-tree)
RB_Node* root; //红黑树的根结点
RB_Node* NIL; //红黑树的叶节点(哨兵)
RB_tree(){
NIL = new RB_Node();
NIL->color = black;
root = NIL;
}
void RB_inorder(RB_Node* x); //中序遍历输出一颗红黑树
void RB_printf(RB_Node* x, int n = 0); //逆时90度输出一颗红黑树
RB_Node* RB_search(RB_Node* x, int k); //查找key值为k的树结点
RB_Node* RB_minnum(RB_Node* x); //查找以x为根结点的树的最小值
RB_Node* RB_maxnum(RB_Node* x); //查找以x为根结点的树的最大值
RB_Node* RB_successor(RB_Node* x); //查找x的后继结点
RB_Node* RB_precursor(RB_Node* x); //查找x的前驱结点
void RB_left_rotate(RB_Node* x); //左旋
void RB_right_rotate(RB_Node* x); //右旋
void RB_insert(RB_Node* x); //插入新的树结点
RB_Node* RB_delete(RB_Node* x); //删除树结点
void RB_insert_fixup(RB_Node *x); //插入结点后,调整红黑树的结构保持红黑树的性质
void RB_delete_fixup(RB_Node *x); //删除结点后,调整红黑树的结构保持红黑树的性质
}T;
三.输出一颗红黑树
1.可以用中序遍历的方式按照排序顺序输出树中的关键字,设x是树结点的某一点,则中序遍历是先输出x的左子树,再输出x结点的值,然后再输出x的右子树
2.有时候按照顺序排序输出一颗红黑树并不能非常直观的看出树的结点之间的关系,可以用稍微修改后的中序遍历方法,逆时针90度输出一颗二叉树。
void RB_tree::RB_inorder(RB_Node *x){ //中序遍历输出一颗红黑树
if (x != NIL){
RB_inorder(x->left);
printf("%d ", x->key);
RB_inorder(x->right);
}
}
void RB_tree::RB_printf(RB_Node *x, int n){ //逆时90度输出一颗红黑树
if (x == NIL){
for (int i = 0; i<n; i++){
printf(" ");
}
printf("NIL\n");
return;
}
RB_printf(x->right, n + 1); //输出右子树
for (int i = 0; i<n; i++){ //输出长为n的" "空格
printf(" ");
}
if (n >= 0){
printf("%d%c-->\n", x->key,x->color?'b':'r'); // 输出该点的数值
}
RB_printf(x->left, n + 1); //输出左子树
}
四.查询红黑树
对于红黑树的性质来说,这查找,查找最大值,前驱后继的过程的时间复杂度都是O(lg(n)),n为树结点个数。
查找
对于红黑树,最常用的操作就是查找树中的一个关键字了。给定指定树根的指针和关键字k,通过函数RB_search返回包含关键字k的结点的指针,不存在则返回NIL。
RB_Node* RB_tree::RB_search(RB_Node *x, int k){
if (x == NIL || k == x->key)
return x;
if (k < x->key)
return RB_search(x->left, k);
else
return RB_search(x->right, k);
}
查找最大关键字元素和最小关键字元素
利用红黑树原本就是一颗二叉查找树的构造的性质,要查找二叉树中具有最小关键字的元素,只要从根结点开始,沿着各结点的left指针查找下去,知道遇到NIL时为止;查找二叉树的具有最大关键字的元素的方法和它对称相反。
RB_Node* RB_tree::RB_minnum(RB_Node* x){
while (x->left != NIL)
x = x->left;
return x;
}
RB_Node* RB_tree::RB_maxnum(RB_Node* x){
while (x->right != NIL)
x = x->right;
return x;
}
查找前驱和后继
如果所有的关键字均不相同,则某一结点x的后继既是具有大于key[x]中的关键字中最小值的那个结点;某一结点x的前驱既是具有小于key[x]中的关键字中最大值的那个结点。
根据二叉搜索树的结构,不用对关键字做任何比较,就可以找出某个结点的前驱和后继。
如果二叉搜索树中某个结点有两个儿子,则其后继没有左儿子,其前驱没有右儿子。
RB_Node* RB_tree::RB_