C++_红黑树的概念及实现

红黑树的概念

红黑树(Red Black Tree) 是一种自平衡二叉搜索树,是在计算机科学中用到的一种数据结构。
红黑树在每个节点上增加一个存储位表示结点的颜色,可以是 Red 或 Black。
过对任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,因而是接近平衡的。

红黑树在二叉搜索树的基础上还满足:

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

红黑树的实现

  • 红黑树的节点定义
enum Color {RED, BLACK};

template <class v>
struct RBTNode
{
    RBTNode(const v& data = v())
     : _left(nullptr)
     , _right(nullptr)
     , _parent(nullptr)
     , _data(data)
     , _color(RED)
    {}
    
    RBTNode<v>* _left; // 节点的左孩子
    RBTNode<v>* _right; // 节点的右孩子
    RBTNode<v>* _parent; // 节点的父亲
    v _data; // 节点的值
    Color _color; // 节点的颜色
};
  • 红黑树的迭代器
template <class v>
class _RBTreeIterator
{
public:
    typedef RBTNode<v>  Node;
    typedef Node*  pNode;
    typedef _RBTreeIterator<v>  self;
   
    _RBTreeIterator(pNode node)
     :_node(node)
    {}
 
    v& operator *()
    {
        return _node->_data;
    }
 
    v* operator ->()
    {
        return &_node->_data;
    }
 
    bool operator!=(const self& it)
    {
        return _node != it._node;
    }
    
    bool operator==(const self& it)
    {
        return _node == it._node;
    }
    
    self& operator++()
    {
        pNode parent = _node->parent;
        if (_node->_right)
        {
            _node = _node->_right;
            while (_node->_left)
            {
                _node = _node->_left;
            }
        }
        else
        {
            while (_node == parent->_right)
            {
                _node = parent;
                parent = parent->parent;
            }
            if (_node->_right != parent)
                _node = parent;
        }
        return *this;
    }
 
    self& operator--()
    {
        pNode parent = _node->parent;
        if (_node->_left)
        {
            _node = _node->_left;
            while (_node->_right)
            {
                _node = _node->_right;
            }
        }
        else
        {
            while (_node != parent->_right)
            {
                _node = parent;
                parent = parent->parent;
            }
            if (_node->_left != parent)
                _node = parent;
         }
         return *this;
    }

private:
    pNode _node;
};
  • 红黑树的结构
template <class k,class v,class kov>
class RBTree
{
public:
    typedef  RBTNode<v>  Node;
    typedef  Node* pNode;
    typedef _RBTreeIterator<v> iterator;

    iterator begin()
    {
        return iterator(_header->_left);
    }
    
    iterator end()
    {
        return iterator(_header);
    }
    
    RBTree(const v& data = v())
    {
        _header = new Node(data);
        _header->_left = _header;
        _header->_right= _header;
        _header->_parent = nullptr;
    }
    
    pair<iterator,bool> Insert(const v& data);//插入值为data的节点
    pNode LeftMost();//返回最左节点的地址
    pNode RightMost();//返回最右节点的地址
    void RotateLeft(pNode parent);//左旋
    void RotateRight(pNode parent);//右旋
    void Inorder();//中序遍历打印
    void _Inorder(pNode root);//中序遍历打印
    bool isRBTree();//验证是否为红黑树
    bool _isRBTree(pNode root,int count,int curcount);//前序遍历验证

private:
    pNode _header;//头节点
};

红黑树的插入

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:

  1. 按照二叉搜索的树规则插入新节点
  2. 检测新节点插入后,红黑树的性质是否造到破坏

新节点的默认颜色是红色,如果其父亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整;当新插入节点的父亲节点颜色为红色时,就违反了性质,不能有连在一起的红色节点,此
时需要对红黑树分情况来讨论:

约定:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

  • 情况一: cur为红,p为红,g为黑,u存在且为红
    将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。
  • 情况二: cur为红,p为红,g为黑,u不存在/u为黑
    p为g的左孩子,cur为p的左孩子,则进行右单旋转;
    相反,p为g的右孩子,cur为p的右孩子,则进行左单旋转;
    p、g变色,p变黑,g变红
  • 情况三: cur为红,p为红,g为黑,u不存在/u为黑
    p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;
    相反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转;
    则转换成了情况2
template<class k, class v, class kov>
inline pair<typename RBTree<k, v, kov>::iterator, bool> RBTree<k, v, kov>::Insert(const v& data)
{
    if (_header->_parent == nullptr)
    {
        pNode root = new Node(data);
        root->_color = BLACK;
        root->_parent = _header;
        _header->_parent = root;
        _header->_left = root;
        _header->_right = root;
        return make_pair(iterator(root), true);    
    }
    pNode cur = _header->_parent;
    pNode parent = nullptr;
    kov kov;
    while (cur)
    {
        parent = cur;
        if (kov(data) > kov(cur->_data))
            cur = cur->_right;
        else if (kov(data) < kov(cur->_data))
            cur = cur->_left;
        else
            return make_pair(iterator(cur), false);
    }
    cur = new Node(data);
    pNode newNode = cur;
    if (kov(data) > kov(parent->_data))
        parent->_right = cur;
    else
        parent->_left = cur;
    cur->_parent = parent;
    while (cur != _header->_parent && cur->_parent->_color == RED)
    {
        pNode parent = cur->_parent;
        pNode gparent = parent->_parent;
        if (parent == gparent->_left)
        {
            pNode unclue = gparent->_right;
            if (unclue && unclue->_color == RED)
            {
                parent->_color = unclue->_color = BLACK;
                gparent->_color = RED;
                cur = gparent;
            }
            else
            {
                if (parent->_right == cur)
                {
                    RotateLeft(parent);
                    swap(parent, cur);
                }
                RotateRight(gparent);
                gparent->_color = RED;
                parent->_color = BLACK;
                break;
            }
         }
         else
         {
             pNode unclue = gparent->_left;
             if (unclue && unclue->_color == RED)
             {
                 parent->_color = unclue->_color = BLACK;
                 gparent->_color = RED;
                 cur = gparent;
             }
             else
             { 
                 if (parent->_left == cur)
                 {
                     RotateRight(parent);
                     swap(parent, cur);
                 }
                 RotateLeft(gparent);
                 gparent->_color = RED;
                 parent->_color = BLACK;
                 break;
             }
         }
     }
     _header->_parent->_color = BLACK;
     _header->_left = LeftMost();
     _header->_right = RightMost();
     return  make_pair(iterator(newNode), true);
}

红黑树的验证

红黑树的验证分为两步:

  1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列);
  2. 检测其是否满足红黑树的性质。
template<class k, class v, class kov>
bool RBTree<k, v, kov>::isRBTree()
{
    if (_header->_parent == nullptr)
        return true;
    if (_header->_parent->_color == RED)
        return false;
    int count = 0;
    pNode cur = _header->_parent;
    while (cur)
    {
        if (cur->_color == BLACK)
        ++count;
        cur = cur->_left;
    }
    return _isRBTree(_header->_parent, count, 0);
}

template<class k, class v, class kov>
bool RBTree<k, v, kov>::_isRBTree(pNode root, int count, int curcount)
{
    if (root == nullptr)
    {
        if (curcount != count)
            return false;
        return true;
    }
    if (root->_color == BLACK)
        ++curcount;
    if (root->_parent->_color == RED && root->_color == RED)
        return false;
    return _isRBTree(root->_left, count, curcount)
     && _isRBTree(root->_right, count, curcount); 
}

其他操作的实现

  • 返回最左节点的地址
template<class k, class v, class kov>
typename RBTree<k,v,kov>::pNode RBTree<k, v, kov>::LeftMost()
{
    pNode cur = _header->_parent;
    while (cur && cur->_left)
        cur = cur->_left;
    return cur;
}
  • 返回最右节点的地址
template<class k, class v, class kov>
typename RBTree<k, v, kov>::pNode RBTree<k, v, kov>::RightMost()
{
    pNode cur = _header->_parent;
    while (cur && cur->_right)
        cur = cur->_right;  
    return cur;
}
  • 左旋
template<class k, class v, class kov>
void RBTree<k, v, kov>::RotateLeft(pNode parent)
{
    pNode subR = parent->_right;
    pNode subRL = subR->_left;
    subR->_left = parent;
    parent->_right = subRL;
    if (subRL)
        subRL->_parent = parent;
    if (parent != _header->_parent)
    {
        if (parent->_parent->_left == parent)
            parent->_parent->_left = subR;
        else
            parent->_parent->_right = subR;
        subR->_parent = parent->_parent;
    }
    else
    {
        _header->_parent = subR;
        subR->_parent = _header;
    }
    parent->_parent = subR;
}
  • 右旋
template<class k, class v, class kov>
void RBTree<k, v, kov>::RotateRight(pNode parent)
{
    pNode subL = parent->_left;
    pNode subLR = subL->_right;
    subL->_right = parent;
    parent->_left = subLR;
    if (subLR)
        subLR->_parent = parent;
    if (parent != _header->_parent)
    {
        if (parent->_parent->_left == parent)       
            parent->_parent->_left = subL;        
        else     
            parent->_parent->_right = subL;        
        subL->_parent = parent->_parent;
    }
    else
    {
        _header->_parent = subL;
        subL->_parent = _header;
    }
    parent->_parent = subL;
}
  • 中序遍历打印
template<class k, class v, class kov>
void RBTree<k, v, kov>::Inorder()
{
    _Inorder(_header->_parent);
    cout << endl;
}

template<class k, class v, class kov>
void RBTree<k, v, kov>::_Inorder(pNode root)
{
    if (root)
    {
        _Inorder(root->_left);
        cout << root->_data.first << " ";
        _Inorder(root->_right);
    }
}

红黑树性能分析

红黑树和AVL树都是高效的平衡二叉树,增删改查的时间复杂度都是O(logN),红黑树不追求绝对平衡,其只需保证最长路径不超过最短路径的2倍,相对而言,降低了插入和旋转的次数,所以在经常进行增删的结构中性能比AVL树更优,而且红黑树实现比较简单,所以实际运用中红黑树更多。

发布了71 篇原创文章 · 获赞 131 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43239560/article/details/99708614
今日推荐