平衡二叉搜索树——红黑树

1.红黑树的简介
红黑树是一棵二叉搜索树,它在每个节点上增加了一个存储位_color来表示节点的颜色,可以是Red或Black。通过对任何一条从根到叶子简单
路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似于平衡。红黑树没有达到AVL树的高度平衡,换句话说,它的高度,并没有AVL树那么高的要求,但他的应用却更加的广泛,实践中是相当高效的,他可以在O(log2 n)的时间内做查找、插入、删除操作。在C++ STL中,set、multiset、map、multimap等都应用到的红黑树的变体。
2.红黑树的性质
(1)每个节点,不是红色就是黑色的
(2) 根节点是黑色的
(3) 如果一个节点是红色的,则它的两个子节点是黑色的
(4) 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。
(5)每个叶子节点都是黑色的(这里的叶子节点是指的NIL节点(空节点))
3.节点的定义

enum Color
{
    RED,
    BLACK
};
//三叉链
template<typename K,typename V>
struct RBTreeNode
{
    RBTreeNode<K, V>* _left;
    RBTreeNode<K, V>* _right;
    RBTreeNode<K, V>* _parent;
    K _key;
    V _value;
    int _color;
    RBTreeNode(const K& key, const V& value)
        :_left(NULL)
        , _right(NULL)
        , _parent(NULL)
        , _key(key)
        , _value(value)
        , _color(RED)
    {}
};

有了AVL树的经验,红黑树旋转的时候并不是调节平衡因子,而是进行颜色。
要知道新插入的结点一定是红色,否则不能满足性质4.

插入操作:
1.树为空直接创建根节点,根节点设置为黑色
2.树不为空,就要分情况讨论了。
1>第一种情况
cur为红,p为红,g为黑,u存在且为红
则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
这里写图片描述
2>第二种情况
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转
p、g变色–p变黑,g变红(如果叔叔存在,cur为调整上来的节点,若叔叔不存在,cur为新插入的结点)
这里写图片描述
3>第三种情况
cur为红,p为红,g为黑,u不存在/u为黑
p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转
则转换成了情况2,但要注意的是第一次旋转之后,cur与parent的位置
这里写图片描述
下面给出插入操作的代码:同样也是先找到插入位置(二叉搜索树的插入)

    bool Insert(const K& key, const V& value)
    {
        if (_root == NULL)
        {
            _root = new Node(key, value);
            _root->_color = BLACK;
            return true;
        }
        else
        {
            Node* parent = NULL;
            Node* cur = _root;
            //找插入位置
            while (cur)
            {
                if (cur->_key > key)
                {
                    parent = cur;
                    cur = cur->_left;
                }
                else if (cur->_key < key)
                {
                    parent = cur;
                    cur = cur->_right;
                }
                else
                    return false;
            }
            cur = new Node(key, value);
            if (parent->_key>key)
            {
                parent->_left = cur;
                cur->_parent = parent;
            }
            else if (parent->_key < key)
            {
                parent->_right = cur;
                cur->_parent = parent;
            }
            while (parent&&parent->_color == RED)
            {
                Node* grandfather = parent->_parent;
                if (parent==grandfather->_left)
                {
                    Node* uncle = grandfather->_right;
                    //叔叔存在且为红
                    if (uncle&&uncle->_color == RED)
                    {
                        parent->_color = BLACK;
                        uncle->_color = BLACK;
                        grandfather->_color = RED;
                        cur = grandfather;
                        parent = cur->_parent;
                    }
                    else//叔叔不存在或者存在为黑色
                    {
                        if (cur == parent->_right)
                        {//2次旋转
                            RotateL(parent);
                            swap(cur, parent);
                        }
                        RotateR(grandfather);
                        parent->_color = BLACK;
                        grandfather->_color = RED;
                    }
                }
                else//parent==grandfather->_right
                {
                    Node* uncle = grandfather->_left;
                    //叔叔存在且为红
                    if (uncle&&uncle->_color == RED)
                    {
                        parent->_color = BLACK;
                        uncle->_color = BLACK;
                        grandfather->_color = RED;
                        cur = grandfather;
                        parent = cur->_parent;
                    }
                    else//叔叔不存在或者存在为黑色
                    {
                        if (cur == parent->_left)
                        {//双旋
                            RotateR(parent);
                            swap(parent, cur);
                        }
                        RotateL(grandfather);
                        parent->_color = BLACK;
                        grandfather->_color = RED;
                    }
                }
            }
        }
        _root->_color = BLACK;
        return true;
    }

左旋右旋代码:

void RotateL(Node* parent)//左旋
        {
            Node* subR = parent->_right;
            Node* subRL = subR->_left;
            parent->_right = subRL;
            if (subRL)
                subRL->_parent = parent;
            subR->_left = parent;
            Node* ppNode = parent->_parent;//subL->_parent = parent->_parent;
            parent->_parent = subR;
            if (ppNode == NULL)
            {
                _root = subR;
                subR->_parent = NULL;
            }
            else
            {
                if (parent == ppNode->_left)
                    ppNode->_left = subR;
                else
                    ppNode->_right = subR;
                subR->_parent = ppNode;
            }
        }
        void RotateR(Node* parent)//右旋
        {
            Node* subL = parent->_left;
            Node* subLR = subL->_right;
            parent->_left = subLR;
            if (subLR)
                subLR->_parent = parent;
            subL->_right = parent;
            Node* ppNode = parent->_parent;
            parent->_parent = subL;
            if (ppNode == NULL)
            {
                _root = subL;
                subL->_parent = NULL;
            }
            else
            {
                if (ppNode->_left == parent)
                {
                    ppNode->_left = subL;
                }
                else
                {
                    ppNode->_right = subL;
                }
                subL->_parent = ppNode;
            }
        }

插入操作结束,我们可以看出没最主要的是其uncle结点的作用。
我们最后来判断一下是否平衡

bool IsBalance()
        {
            if (_root == NULL)
                return true;
            if (_root&&_root->_color == RED)
                return false;
            int num = 0;
            int blacknum = 0;
            //求最左分支的黑结点的个数
            Node* left = _root;
            while (left)
            {
                if (left->_color == BLACK)
                {
                    ++blacknum;
                }
                left = left->_left;
            }
            return _IsBalance(_root, blacknum, num);
        }
        bool _IsBalance(Node* root, const int blacknum, int num)
        {
            if (root == NULL)
            {
                return true;
            }
            if (root->_color == RED&&root->_parent->_color == RED)
            {
                cout << "有两个连续的红结点" << endl;
                return false;
            }
            if (root->_color == BLACK)
            {
                ++num;
            }
            if (root->_left == NULL && root->_right == NULL && num!=blacknum )
            {
                return false;
            }
            return _IsBalance(root->_left, blacknum, num)
                && _IsBalance(root->_right, blacknum, num);
        }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值