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

来源:互联网 发布:河师大教务网络系统 编辑:程序博客网 时间:2024/06/09 03:54

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 0
原创粉丝点击