红黑树概念
红黑树是一种含有红黑两种结点并且能够自平衡的二叉查找树。
划重点:红黑结点,自平衡,二叉查找树。
红黑树也是二叉查找树的一种,实现这一点并不难,它主要困难在自平衡的处理。
红黑树的性质:
(它在每个节点增加了一个存储位来记录节点的颜色,red或black)
(每条性质都很重要!!!)
- 每个节点要么是黑色,要么是红色。
- 根节点是黑色
- 每个叶节点是黑色
- 每个红色结点的两个子节点一定都是黑色(不会出现连续的两个红色结点)
- 任意一结点到每个叶节点的路径上都包含数量的黑结点
- 如果一个节点是黑节点,那么它一定有两个子节点
红黑树跟AVL树不同,它不需要满足完美平衡二叉查找树
但左子树和右子树的黑结点的层数是相等的,也即任意一个节点到每个叶节点的路径都包含数量相同的黑结点,我们把红黑树这种平衡称为黑色完美平衡。
产生原因
老生常谈,还是为了减小时间复杂度或者操作复杂程度。
AVL树的时间复杂度略优于红黑树,但红黑树旋转情况少于AVL树,因此插入删除操作会更加容易控制。
红黑树的整体性能略优于AVL树。
红黑树的自平衡
红黑树的自平衡基于三种操作:
- 左旋
- 右旋
- 变色
(今天累啦,先写到这里,操作下次再补充吧)
红黑树的ADT
- 查找
查找不会破坏树的平衡,因此查找操作和二叉查找树相同
1)从根节点开始查找,把根节点设置为当前节点,若当前节点为空,返回NULL
2)当前节点不为空,用当前节点的key跟查找key作比较,当前节点key等于查找key,则返回当前节点;若当前节点key大于查找key,把当前节点的左子节点设置为当前节点,之后递归。若当前节点key小于查找key,当前节点设置为右子节点,之后递归。
划重点:红黑树的查找时间复杂度同样为log(N) - 插入
插入分为两大步骤:查找到插入的位置,插入后保持树平衡
1)从根节点开始查找,根节点为空,把插入节点作为根节点,end
2)根节点不为空,根节点作为当前节点,不断用左节点或右节点替换,直到当前节点为null,返回当前节点的父节点,end。
3)当前节点key等于查找key,那么该key所在节点为插入节点,更新节点值,end
4)当前节点key大于查找key,当前节点的左子节点设置为当前节点,重复
5)小于时,吧当前节点的右子节点设置为当前节点,重复
划重点:插入节点到达正确位置之后,把插入节点定义为红色(红色结点在父结点为黑色时,红黑树的黑色平衡没被破坏)
判断一棵二叉树是否为红黑树
根据以上给出的性质进行判断,代码如下:
/*judge whether the tree is a Red-Black tree*/
bool JudgeRBTree(PRBTree T)
{
/*empty tree is considered to be an RBtree*/
if (T == NULL)
return true;
/*case 1:root node is red, then return false*/
if (T->color == 0)
return false;
/*case 2:compute the number of black nodes in the left subtree*/
/*if the number of black nodes in the right subtree is the same
as that in the left subtree,then it proves to be a Red-Black tree
otherwise, it is not*/
int count = 0;
RBnode *cur = T;
while (cur != NULL)
{
if (cur->color == 1)
count++;
cur = cur->left;
}
/*Number records the number of black nodes on each path,
and count is used to mark the number of black nodes on the left subtree*/
int number = 0;
return _JudgeRBTree(T, count, number);
}
bool _JudgeRBTree(PRBTree T, int count, int number)
{
if (T == NULL)
return true;
/*case 3:continuous red nodes,return false*/
if (((T->color == 0 && (T->left != NULL || T->right != NULL))) && ((T->left->color == 0) || (T->right->color == 0)))
{
printf("%d ", T->key);
printf("There are continuous red nodes!\n");
return false;
}
if (T->color == 1)
number++;
/*Leaf node, here we can be used to judge
whether the number of black knots is equal*/
if (T->left == NULL && T->right == NULL)
{
if (number != count)
{
printf("%d ", T->key);
printf("The number of black nodes is different!\n");
return false;
}
}
return _JudgeRBTree(T->left, count, number) && _JudgeRBTree(T->right, count, number);
}
//测试数据
/*7 -2 1 0 0 5 -4 0 0 0 -11 8 0 0 14 0 -15 0 0*/
/*35 -5 3 0 0 22 -9 0 0 0 47 -40 0 0 0*/
/*11 -2 1 0 0 -7 5 -4 0 0 0 8 0 0 14 0 -15 0 0*/
/*10 -7 5 0 6 0 0 8 0 0 15 -11 0 0 17 0 0*/