二叉查找树之红黑树(RBTree)

红黑树概念

红黑树是一种含有红黑两种结点并且能够自平衡二叉查找树

划重点:红黑结点,自平衡,二叉查找树。
红黑树也是二叉查找树的一种,实现这一点并不难,它主要困难在自平衡的处理。

红黑树的性质:
(它在每个节点增加了一个存储位来记录节点的颜色,red或black)
(每条性质都很重要!!!)

  1. 每个节点要么是黑色,要么是红色。
  2. 根节点是黑色
  3. 每个叶节点是黑色
  4. 每个红色结点的两个子节点一定都是黑色(不会出现连续的两个红色结点)
  5. 任意一结点到每个叶节点的路径上都包含数量的黑结点
  6. 如果一个节点是黑节点,那么它一定有两个子节点

红黑树跟AVL树不同,它不需要满足完美平衡二叉查找树

但左子树和右子树的黑结点的层数是相等的,也即任意一个节点到每个叶节点的路径都包含数量相同的黑结点,我们把红黑树这种平衡称为黑色完美平衡

产生原因

老生常谈,还是为了减小时间复杂度或者操作复杂程度。
AVL树的时间复杂度略优于红黑树,但红黑树旋转情况少于AVL树,因此插入删除操作会更加容易控制。
红黑树的整体性能略优于AVL树

红黑树的自平衡

红黑树的自平衡基于三种操作:

  1. 左旋
  2. 右旋
  3. 变色
    (今天累啦,先写到这里,操作下次再补充吧)

红黑树的ADT

  1. 查找
    查找不会破坏树的平衡,因此查找操作和二叉查找树相同
    1)从根节点开始查找,把根节点设置为当前节点,若当前节点为空,返回NULL
    2)当前节点不为空,用当前节点的key跟查找key作比较,当前节点key等于查找key,则返回当前节点;若当前节点key大于查找key,把当前节点的左子节点设置为当前节点,之后递归。若当前节点key小于查找key,当前节点设置为右子节点,之后递归。
    划重点:红黑树的查找时间复杂度同样为log(N)
  2. 插入
    插入分为两大步骤:查找到插入的位置,插入后保持树平衡
    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*/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值