红黑树(C++实现)

目录

红黑树的概念

红黑树的性质

红黑树的结构

红黑树的插入操作

1.按照二叉搜索的树规则插入新节点

2.检测新节点插入后,红黑树的性质是否造到破坏

红黑树的删除

红黑树的验证

红黑树的应用

红黑树与AVL树的比较

红黑树代码文件


红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡

红黑树的性质

◉ 每个结点不是红色就是黑色

◉ 根节点是黑色的

◉ 如果一个节点是红色的,则它的两个孩子结点是黑色的一条路径中,没有连续红色节点

◉ 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点每条路径黑色节点数量是相等

◉ 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)NIL节点

思考:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?(最短路径*2 >= 最长路径

红黑树的结构

为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点,如下:

红黑树的插入操作

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

1.按照二叉搜索的树规则插入新节点

2.检测新节点插入后,红黑树的性质是否造到破坏

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

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

◉ 情况一:cur为红,p为红,g为黑,u存在且为红

解法方式:

将p,u改为黑,g改为红,然后把g当成cur,继续向上调整

如果g为根节点,直接改为黑即可

 注意:此处所看到的树,可能是一棵完整的树,也可能是一棵子树

 

 

◉ 情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑(单旋)(cur p g单纯一条直线,纯粹某边高,单旋)

如果叔叔存在且为黑,一定是从情况一变过来的,在这里cur不是新插入节点,所以cur是黑

解决方式:

1️⃣ p为g的左孩子,cur为p的左孩子,则进行右单旋转

2️⃣ p为g的右孩子,cur为p的右孩子,则进行左单旋转

---->p变黑,g变红

 

 

 

 

◉ 情况三: cur为红,p为红,g为黑,u不存在/u存在且为黑(双旋)(cur p g 不在一条直线上,不是单纯的某边高)

p为g的左孩子,cur为p的右孩子,则对p先进行左单旋,回到情况二 再对g进行右单旋

p为g的右孩子,cur为p的左孩子,则对p先进行右单旋,回到情况二 再对g进行左单旋

先变色后旋转二次 --> cur变黑 g变红

 

 

 

说明:u的情况有两种

◉ 如果u节点不存在,则cur一定是新插入节点,因为如果cur不是新插入节点,则cur和p一定有一个节点的颜色是黑色,就不满足性质4:每条路径黑色节点个数相同

◉ 如果u节点存在,则其一定是黑色的,那么cur节点原来的颜色一定是黑色的,现在看到红色的原因是因为cur的子树在调整的过程中将cur节点的颜色由黑色改成红色。

基本的情况就到这里,剩下的都是镜像方法相同,不多赘述

    bool Insert(const pair<K, V>& kv){
        // 树为空,插入节点为新根节点
        if(_root == nullptr){
            _root = new Node(kv);
            _root->_col = BLACK;
            return true;
        }
        
        Node* parent = nullptr;
        Node* cur = _root;
        
        //找到插入位置
        while (cur)
        {
            if (cur->_kv.first < kv.first)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_kv.first > kv.first)
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;
            }
        }

        //新增节点。颜色给红色
        cur = new Node(kv);
        cur->_col = RED;
        
        if (parent->_kv.first < kv.first)
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }
        cur->_parent = parent;

        
        while(parent && parent->_col == RED){
            Node* grandfather = parent->_parent;
            //     g
            //  p     u
            if(parent == grandfather->_left){
                Node* uncle = grandfather->_right;
                if (uncle && uncle->_col == RED) {
                    //情况一 :叔叔存在且为红
                    //变色 + 继续往上处理 p u 变黑 g变红
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    
                    cur = grandfather;
                    parent = cur->_parent;
                    
                }
                else{
                    //情况二:叔叔不存在或者存在为黑 --》旋转+变色
                    if(cur == parent->_left){
                        //    g
                        //  p   u
                        //c
                        //单旋:gpc一边高
                        RotateR(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }else{
                        //    g
                        //  p   u
                        //    c
                        //双旋:pgc两段高
                        RotateL(parent);
                        RotateR(grandfather);
                        
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    
                    break;
                }
            }
            else{
                //    g
                //  u   p
                Node* uncle = grandfather->_left;
                // 叔叔存在且为红,-》变色即可
                if (uncle && uncle->_col == RED)
                {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    
                    // 继续往上处理
                    cur = grandfather;
                    parent = cur->_parent;
                }
                else // 叔叔不存在,或者存在且为黑
                {
                    // 情况二:叔叔不存在或者存在且为黑
                    // 旋转+变色
                    //      g
                    //   u     p
                    //            c
                    if (cur == parent->_right)
                    {
                        RotateL(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    else
                    {
                        //        g
                        //   u     p
                        //      c
                        RotateR(parent);
                        RotateL(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
                
            }
        }
        _root->_col = BLACK;
        return true;

        
    }

 

红黑树的删除

红黑树的删除本节不做讲解,有兴趣的同学可参考:《算法导论》或者《STL源码剖析》

红黑树 - _Never_ - 博客园

红黑树的验证

红黑树的验证分为两步:

◉ 检测其是否满足二叉搜索树(中序遍历是否为有序序列)

◉ 检测其是否满足红黑树的性质

具体验证细节等放项目代码文件中

红黑树的应用

◉ C++ STL库 -- map/set、mutil_map/mutil_set

◉ Java 库

◉ linux内核

◉ 其他一些库

http://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html

红黑树与AVL树的比较

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

红黑树代码文件

//
//  RBTree.h
//  红黑树
//
//  Created by 南毅 on 2024/7/22.
//
#include <iostream>
using namespace std;
#include <assert.h>
#include <vector>
#include <time.h>

enum Colour{
    RED,
    BLACK
};

template<class K, class V>
struct RBTreeNode
{
    pair<K, V> _kv;
    RBTreeNode<K, V>* _left;
    RBTreeNode<K, V>* _right;
    RBTreeNode<K, V>* _parent;
    Colour _col;

    RBTreeNode(const pair<K, V>& kv)
        :_left(nullptr)
        , _right(nullptr)
        , _parent(nullptr)
        , _kv(kv)
        , _col(RED)
    {}
};


template<class K, class V>
class RBTree
{
public:
    int _rotateNum = 0;
private:
    typedef RBTreeNode<K, V> Node;
    Node* _root = nullptr;
    
    void RotateL(Node* parent)
    {
        _rotateNum++;
        Node* subR = parent->_right;
        Node* subRL = subR->_left;

        parent->_right = subRL;
        if (subRL)
            subRL->_parent = parent;

        Node* parentParent = parent->_parent;

        subR->_left = parent;
        parent->_parent = subR;

        if (parentParent == nullptr)
        {
            _root = subR;
            subR->_parent = nullptr;
        }
        else
        {
            if (parent == parentParent->_left)
            {
                parentParent->_left = subR;
            }
            else
            {
                parentParent->_right = subR;
            }

            subR->_parent = parentParent;
        }
    }

    void  RotateR(Node* parent)
    {
        _rotateNum++;

        Node* subL = parent->_left;
        Node* subLR = subL->_right;

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

        Node* parentParent = parent->_parent;

        subL->_right = parent;
        parent->_parent = subL;

        if (parentParent == nullptr)
        {
            _root = subL;
            subL->_parent = nullptr;
        }
        else
        {
            if (parent == parentParent->_left)
            {
                parentParent->_left = subL;
            }
            else
            {
                parentParent->_right = subL;
            }

            subL->_parent = parentParent;
        }

    }
    
    void Destroy(Node* root)
    {
        if (root == nullptr)
            return;

        Destroy(root->_left);
        Destroy(root->_right);
        delete root;
    }

    Node* Copy(Node* root)
    {
        if (root == nullptr)
            return nullptr;

        Node* newRoot = new Node(root->_kv);
        newRoot->_left = Copy(root->_left);
        newRoot->_right = Copy(root->_right);

        return newRoot;
    }
    
    bool Check(Node* root, int blackNum, const int refNum)
        {
            if (root == nullptr)
            {
                //cout << blackNum << endl;
                if (refNum != blackNum)
                {
                    cout << "存在黑色节点的数量不相等的路径" << endl;
                    return false;
                }

                return true;
            }

            if (root->_col == RED && root->_parent->_col == RED)
            {
                cout << root->_kv.first << "存在连续的红色节点" << endl;
                return false;
            }

            if (root->_col == BLACK)
            {
                blackNum++;
            }

            return Check(root->_left, blackNum, refNum)
                && Check(root->_right, blackNum, refNum);
        }

        int _Size(Node* root)
        {
            return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;
        }

        int _Height(Node* root)
        {
            if (root == nullptr)
                return 0;

            int leftHeight = _Height(root->_left);
            int rightHeight = _Height(root->_right);

            return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
        }

        void _InOrder(Node* root)
        {
            if (root == nullptr)
            {
                return;
            }

            _InOrder(root->_left);
            cout << root->_kv.first << ":" << root->_kv.second << endl;
            _InOrder(root->_right);
        }

public:
    RBTree() = default;

    RBTree(const RBTree& t)
    {
        _root = Copy(t._root);
    }

    RBTree& operator=(RBTree t)
    {
        swap(_root, t._root);
        return *this;
    }

    ~RBTree()
    {
        Destroy(_root);
        _root = nullptr;
    }
    
    bool Insert(const pair<K, V>& kv){
        // 树为空,插入节点为新根节点
        if(_root == nullptr){
            _root = new Node(kv);
            _root->_col = BLACK;
            return true;
        }
        
        Node* parent = nullptr;
        Node* cur = _root;
        
        //找到插入位置
        while (cur)
        {
            if (cur->_kv.first < kv.first)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_kv.first > kv.first)
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;
            }
        }

        //新增节点。颜色给红色
        cur = new Node(kv);
        cur->_col = RED;
        
        if (parent->_kv.first < kv.first)
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }
        cur->_parent = parent;

        
        while(parent && parent->_col == RED){
            Node* grandfather = parent->_parent;
            //     g
            //  p     u
            if(parent == grandfather->_left){
                Node* uncle = grandfather->_right;
                if (uncle && uncle->_col == RED) {
                    //情况一 :叔叔存在且为红
                    //变色 + 继续往上处理 p u 变黑 g变红
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    
                    cur = grandfather;
                    parent = cur->_parent;
                    
                }
                else{
                    //情况二:叔叔不存在或者存在为黑 --》旋转+变色
                    if(cur == parent->_left){
                        //    g
                        //  p   u
                        //c
                        //单旋:gpc一边高
                        RotateR(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }else{
                        //    g
                        //  p   u
                        //    c
                        //双旋:pgc两段高
                        RotateL(parent);
                        RotateR(grandfather);
                        
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    
                    break;
                }
            }
            else{
                //    g
                //  u   p
                Node* uncle = grandfather->_left;
                // 叔叔存在且为红,-》变色即可
                if (uncle && uncle->_col == RED)
                {
                    parent->_col = uncle->_col = BLACK;
                    grandfather->_col = RED;
                    
                    // 继续往上处理
                    cur = grandfather;
                    parent = cur->_parent;
                }
                else // 叔叔不存在,或者存在且为黑
                {
                    // 情况二:叔叔不存在或者存在且为黑
                    // 旋转+变色
                    //      g
                    //   u     p
                    //            c
                    if (cur == parent->_right)
                    {
                        RotateL(grandfather);
                        parent->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    else
                    {
                        //        g
                        //   u     p
                        //      c
                        RotateR(parent);
                        RotateL(grandfather);
                        cur->_col = BLACK;
                        grandfather->_col = RED;
                    }
                    break;
                }
                
            }
        }
        _root->_col = BLACK;
        return true;

        
    }
    
    void InOrder()
    {
        _InOrder(_root);
        cout << endl;
    }

    int Height()
    {
        return _Height(_root);
    }

    int Size()
    {
        return _Size(_root);
    }

    bool IsBalance()
    {
        if (_root == nullptr)
            return true;

        if (_root->_col == RED)
        {
            return false;
        }
        
        // 参考值
        int refNum = 0;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_col == BLACK)
            {
                ++refNum;
            }

            cur = cur->_left;
        }

        return Check(_root, 0, refNum);
    }

    Node* Find(const K& key)
    {
        Node* cur = _root;
        while (cur)
        {
            if (cur->_kv.first < key)
            {
                cur = cur->_right;
            }
            else if (cur->_kv.first > key)
            {
                cur = cur->_left;
            }
            else
            {
                return cur;
            }
        }

        return nullptr;
    }


};


void TestRBTree1()
{
    RBTree<int, int> t;
    //int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    for (auto e : a)
    {
        /*if (e == 9)
        {
            int i = 0;
        }*/

        t.Insert({ e, e });

        //cout << e << "->" << t.IsBalanceTree() << endl;
    }

    t.InOrder();
    cout << t.IsBalance() << endl;
}

void TestRBAVLTree()
{
    const int N = 10000000;
    vector<int> v;
    v.reserve(N);
    srand(time(0));

    for (size_t i = 0; i < N; i++)
    {
        v.push_back(i);
        //v.push_back(rand() + i);
    }

    size_t begin2 = clock();
    RBTree<int, int> rbt;
    for (auto e : v)
    {
        rbt.Insert(make_pair(e, e));
    }
    size_t end2 = clock();

    cout << "RB Insert:" << end2 - begin2 << endl;

    size_t begin3 = clock();
    AVLTree<int, int> avlt;

    for (auto e : v)
    {
        avlt.Insert(make_pair(e, e));
    }
    size_t end3 = clock();
    cout << "AVL Insert:" << end3 - begin3 << endl;

    cout << "RB Height:" << rbt.Height() << endl;
    cout << "AVL Height:" << avlt.Height() << endl;
    cout << "RB 旋转次数:" << rbt._rotateNum << endl;
    cout << "AVL 旋转次数:" << avlt._rotateNum << endl;

    cout << "Size:" << rbt.Size() << endl;

    size_t begin1 = clock();

    // 确定在的值
    /*for (auto e : v)
    {
        rbt.Find(e);
    }*/

    // 随机值
    for (size_t i = 0; i < N; i++)
    {
        rbt.Find((rand() + i));
    }

    size_t end1 = clock();

    cout << "RB Find:" << end1 - begin1 << endl;

    size_t begin4 = clock();

    // 确定在的值
    for (auto e : v)
    {
        avlt.Find(e);
    }

    // 随机值
    /*for (size_t i = 0; i < N; i++)
    {
        avlt.Find((rand() + i));
    }*/

    size_t end4 = clock();

    cout << "AVL Find:" << end4 - begin4 << endl;
}

int main(){
    TestRBAVLTree();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值