红黑树—RBTree

  红黑树是一棵二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,可以是Red或Black。通过对任何一条从根到叶子简单路径上的颜色来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似于平衡。

红黑树是满足下面红黑性质的二叉搜索树:

  1. 每个节点,不是红色就是黑色的
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个子节点是黑色的(没有连续的红节点)
  4. 对每个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点。(每条路径的黑色结点数量相等)
  5. 每个叶子节点都是黑色的(这里的叶子节点是指的NIL节点(空节点))

如:
红黑树

具体实现:

#pragma once

#include <stdlib.h>
#include <iostream>

using namespace std;

enum Color
{
    RED,
    BLACK,
};

template<class K, class V>
struct RBTreeNode
{
    K _key;
    V _value;
    RBTreeNode<K, V>* _left;
    RBTreeNode<K, V>* _right;
    RBTreeNode<K, V>* _parent;

    Color _color;   //颜色

    RBTreeNode(const K& key, const V& value)
        :_key(key)
        , _value(value)
        , _left(NULL)
        , _right(NULL)
        , _parent(NULL)
        , _color(RED)               //默认结点颜色是红色
    {}
};

template<class K, class V>
class RBTree
{
    typedef RBTreeNode<K, V> Node;
public:
    RBTree()
        :_root(NULL)
    {}
    RBTree(const RBTree<K, V>& tree)
    {
        _Copy(tree._root, _root);
    }
    RBTree<K, V>& operator=(const RBTree<K, V>& tree)
    {
        if (this != &tree)
        {
            RBTree<K, V> tmp(tree);
            swap(_root, tmp._root);
        }
        return *this;
    }
    ~RBTree()
    {
        _Destory(_root);
    }
    bool Insert(const K& key, const V& value)
    {
        if (_root == NULL)                 //空树时直接插入
        {
            _root = new Node(key, value);
            _root->_color = BLACK;
            return true;
        }
        Node* parent = NULL;
        Node* cur = _root;
        while (cur)                       //寻找插入的位置
        {
            if (cur->_key < key)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_key > key)
            {
                parent = cur;
                cur = cur->_left;
            }
            else{
                return false;           //要出入节点已经存在,不支持插入
            }
        }
        cur = new Node(key, value);
        cur->_color = RED;
        if (parent->_key < key)
        {
            parent->_right = cur;
            cur->_parent = parent;
        }
        else
        {
            parent->_left = cur;
            cur->_parent = parent;
        }
        while (parent && parent->_color == RED)              //父节点为红色,需要进行调整
        {
            Node* grand = parent->_parent;                  //祖父结点
            if (parent == grand->_left)
            {
                Node* uncle = grand->_right;                //叔叔节点
                //1.叔叔节点存在且为红
                if (uncle && uncle->_color == RED)
                {
                    parent->_color = uncle->_color = BLACK;
                    grand->_color = RED;

                    cur = grand;
                    parent = cur->_parent;                 //继续向上判断
                }
                //2.叔叔节点不存在,存在且为黑
                else
                {
                    if (cur == parent->_right)
                    {
                        RotateL(parent);                  //先对parent进行左旋
                        swap(cur, parent);
                    }
                    RotateR(grand);                      //对祖父结点右旋
                    parent->_color = BLACK;
                    grand->_color = RED;
                }
            }
            else
            {
                Node* uncle = grand->_left;
                //1.叔叔节点存在且为红
                if (uncle && uncle->_color == RED)
                {
                    parent->_color = BLACK;
                    uncle->_color = BLACK;
                    grand->_color = RED;

                    cur = grand;
                    parent = cur->_parent;
                }
                //2.叔叔节点不存在,存在且为黑
                else
                {
                    if (cur == parent->_left)
                    {
                        RotateR(parent);
                        swap(cur, parent);
                    }
                    RotateL(grand);
                    parent->_color = BLACK;
                    grand->_color = RED;
                }
            }
        }
        _root->_color = BLACK;               //强制将根节点变为黑色
        return true;
    }
    bool Remove(const K& key)
    {
        Node* cur = _root;
        Node* parent = NULL;
        Node* del = NULL;
        while (cur)                 //寻找待删除结点
        {
            if (cur->_key > key)
            {
                cur = cur->_left;
            }
            else if (cur->_key < key)
            {
                cur = cur->_right;
            }
            else
            {
                break;
            }
        }
        if (cur == NULL)
        {
            return false;                //要删除节点不存在,删除失败
        }
        del = cur;
        //如果要删除的结点有两个孩子,则需找到右子树的最左结点
        if (cur->_left != NULL && cur->_right != NULL)
        {
            cur = cur->_right;
            while (cur->_left)
            {
                cur = cur->_left;
            }
            del->_key = cur->_key;
            del->_value = cur->_value;
            del = cur;                  //交换后使del指向要删除的结点
        }
        parent = cur->_parent;           //找到要删除节点的父亲
        if (cur->_left == NULL)          //要删除节点的左孩子为空,或者都为空
        { 
            if (parent == NULL)          //要删除的是头结点
            {
                _root = cur->_right;
                if (cur->_right)
                {
                    _root->_parent = NULL;
                    _root->_color = BLACK;        //记得根节点永远是黑色
                }
                delete del;
                return true;
            }
            else
            {
                if (parent->_left == cur)
                {
                    parent->_left = cur->_right;
                }
                else
                {
                    parent->_right = cur->_right;
                }
                if (cur->_right)
                {
                    cur->_right->_parent = parent;
                }
            }
            cur = del->_right;               //cur更新到要删除节点的右子树
        }
        else                                //要删除节点的右孩子为空
        {
            if (parent == NULL)              //要删除节点为根节点
            {
                _root = cur->_left;
                _root->_parent = NULL;
                _root->_color = BLACK;
                delete del;
                return true;
            }
            else
            {
                if (parent->_left == cur)
                {
                    parent->_left = cur->_left;
                }
                else
                {
                    parent->_right = cur->_left;
                }
                cur->_left->_parent = parent;
            }
            cur = del->_left;
        }

        //根据颜色判断删除后是否还是合法的红黑树,若不合法则旋转
        if (del->_color == RED)            //要删除结点是红色,则删除后任然平衡,无需旋转
        {
            delete del;
            return true;
        }
        if (del->_color == BLACK && cur && cur->_color == RED)     //如果要删除节点是黑色,且它的孩子是红色            
        {                                                       //则将孩子变为黑色即可
            cur->_color = BLACK;
            delete del;
            return true;
        }
        //要删除节点是黑色,且它的孩子为NULL或为黑色
        while (parent)
        {
            if (parent->_left == cur)           //要删除节点是父节点的左孩子
            {
                Node* subR = parent->_right;
                if (subR->_color == RED)
                {
                    RotateL(parent);            //对parent左旋,染色
                    subR->_color = BLACK;
                    parent->_color = RED;
                }
                else                           //subR是黑色的
                {
                    Node* subRL = subR->_left;
                    Node* subRR = subR->_right;
                    if (parent->_color == BLACK && (subRL == NULL && subRR == NULL) ||
                        (subRL && subRL->_color == BLACK && subRR && subRR->_color == BLACK))
                    {
                        subR->_color = RED;     //使subR这条路径上减少一个黑色结点,再向上判断
                        cur = parent;
                        parent = cur->_parent;
                    }
                    else
                    {
                        if (parent->_color == RED)
                        {
                            if ((subRL == NULL && subRR == NULL) ||
                                (subRL && subRL->_color == BLACK && subRR && subRR->_color == BLACK))
                            {
                                parent->_color = BLACK;     //将父节点变为黑色
                                subR->_color = RED;
                                break;
                            }
                        }
                        if (subRL->_color == RED)           //subRL为红色,先对subR进行右旋转换为左单旋情况
                        {
                            RotateR(subR);
                            subR = subRL;
                        }
                        RotateL(parent);
                        //将旋转后新的父节点变为与原来父节点一样的颜色
                        if (parent->_color == RED)         
                        {
                            subR->_color = RED;
                        }
                        else
                        {
                            subR->_color = BLACK;
                        }
                        //将原来的父节点染黑
                        parent->_color = BLACK;
                        subR->_right->_color = BLACK;       //由于subR的右子树少一个黑结点
                        break;
                    }
                }
            }
            else                                          //要删除节点是父节点的右孩子
            {
                Node* subL = parent->_left;
                if (subL->_color == RED)
                {
                    RotateR(parent);                       //对parent右旋,染色
                    parent->_color = RED;
                    subL->_color = BLACK;
                }
                else                                      //parent的左孩子是黑的
                {
                    Node* subLR = subL->_right;
                    Node* subLL = subL->_left;
                    //如果父节点和subL都是黑的,subL的孩子要么全空,要么全黑
                    if (parent->_color == BLACK && (subLL == NULL && subLR == NULL) ||
                        (subLL && subLL->_color == BLACK && subLR && subLR->_color == BLACK))
                    {
                        subL->_color = RED;               //使subL这条路径上减少一个黑色结点,再向上判断
                        cur = parent;
                        parent = cur->_parent;
                    }
                    else
                    {
                        if (parent->_color == RED)
                        {
                            if ((subLL == NULL && subLR == NULL) ||
                                (subLL && subLL->_color == BLACK && subLR && subLR->_color == BLACK))
                            {
                                parent->_color = BLACK;            //cur路径增加一个黑节点
                                subL->_color = RED;                //subL路径黑节点个数不变
                                break;
                            }
                        }
                        if (subLR->_color == RED)                  //subLR为红色,先对subL进行左旋转换为右单旋情况
                        {
                            RotateL(subL);
                            subL = subLR;
                        }
                        RotateR(parent);
                        //将旋转后新的父节点变为与原来父节点一样的颜色
                        if (parent->_color == RED)
                        {
                            subL->_color = RED;
                        }
                        else
                        {
                            subL->_color = BLACK;
                        }
                        //将原来的父节点染黑
                        parent->_color = BLACK;
                        subL->_left->_color = BLACK;
                        break;
                    }
                }
            }
        }

        _root->_color = BLACK;
        delete del;
        return true;
    }
    bool Find(const K& key)
    {
        Node* cur = _root;
        while (cur)
        {
            if (cur->_key < key)
            {
                cur = cur->_right;
            }
            else if (cur->_key > key)
            {
                cur = cur->_left;
            }
            else
            {
                return true;
            }
        }
        return false;
    }
    void InOrder()
    {
        _InOrder(_root);
        cout << endl;
    }
    bool IsBalance()
    {
        if (_root == NULL)
        {
            return true;
        }
        if (_root->_color == RED)
        {
            return false;
        }
        int count = 0;             //用count统计最左支路的黑节点个数
        Node* cur = _root;
        while (cur)
        {
            if (cur->_color == BLACK)
            {
                ++count;
            }
            cur = cur->_left;
        }
        int num = 0;
        return _IsBalance(_root, count, num);
    }
protected:
    void _Copy(Node* root, Node* new_root)
    {
        if (root == NULL)
        {
            return;
        }
        Node* cur = new Node(root->_key, root->_value);
        cur->_color = root->_color;

        new_root = cur;
        cur->_parent = new_root;
        _Copy(root->_left, cur->_left);
        _Copy(root->_right, cur->_right);
    }
    void _Destory(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        _Destory(root->_left);
        _Destory(root->_right);
        delete root;
    }
    void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        Node* ppNode = parent->_parent;

        parent->_left = subLR;
        if (subLR)
        {
            subLR->_parent = parent;
        }

        subL->_right = 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;
        }
    }
    void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        Node* ppNode = parent->_parent;

        parent->_right = subRL;
        if (subRL)
        {
            subRL->_parent = parent;
        }
        subR->_left = parent;
        parent->_parent = subR;

        if (ppNode == NULL)
        {
            _root = subR;
            subR->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
            {
                ppNode->_left = subR;
            }
            else
            {
                ppNode->_right = subR;
            }
            subR->_parent = ppNode;
        }
    }
    void _InOrder(Node* root)
    {
        if (root == NULL)
        {
            return;
        }
        _InOrder(root->_left);
        cout << root->_key << " ";
        _InOrder(root->_right);
    }
    bool _IsBalance(Node* root, const int& count, int num)
    {
        if (root == NULL)
        {
            return num == count;
        }
        //存在连续红节点,表示不平衡
        if (root->_color == RED && root->_parent->_color == RED)
        {
            cout << "存在连续红节点:" << root->_key << endl;
            return false;
        }
        if (root->_color == BLACK)
        {
            ++num;
        }
        return _IsBalance(root->_left, count, num) && _IsBalance(root->_right, count, num);
    }
private:
    Node* _root;
};

void TestRBTree()
{
    int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    RBTree<int, int> t;
    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
    {
        t.Insert(a[i], i);
        cout << a[i] << ":" << t.IsBalance() << endl;
    }
    t.InOrder();
    cout << t.IsBalance() << endl;
    cout << t.Find(16) << endl;
    cout << t.Find(10) << endl;
    t.Remove(11);
    t.InOrder();
    cout << t.IsBalance() << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值