为什么红黑树如此受欢迎
创始人
2024-05-31 20:35:43
0

平衡二叉查找树有很多,但是我们一提到平衡二叉查找树,常提及的就是红黑树,它的“出镜率”甚至要高于平衡二叉查找树。

红黑树是一种相对平衡的二叉查找树,不符合严格意义上平衡二叉查找树的定义。

目录

红黑树的插入

 红黑树的验证


红黑树的性质

  • 每个结点不是红色就是黑色
  • 根节点是黑色的 
  • 任何上下相邻的节点不能同时为红色 如果一个节点是红色的,则它的两个孩子结点是黑色的 
  •  对于每个结点,从该结点到其所有后代叶结点的所有路径,都包含相同数目的黑色结点 
  • 每个叶子结点都是黑色的空节点,也就是说,叶子节点不存储数据。

满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍。

红黑树的性能分析

假设每条路径上的黑节点是N,最短的路径全是黑节点,最长的路径节点一个黑节点一个红节点相间 ,N<=任意路径长度<=2N。

平衡二叉查找树的提出是为了解决二叉查找树因为动态更新导致的性能退化问题。因此,“平衡”可以等价为性能不退化,“近似平衡”就等价为性能退化不太严重。二叉查找树的很多操作的时间复杂度与树的高度成正比。一颗极其平衡的二叉树(满二叉树或完全二叉树)的高度大约是log n,如果要证明红黑树是近似平衡的,只需要证明红黑树的高度近似于log n(比如同一量级)。

证明:

 红黑树的最长路径不会超过2log n,也就是说,红黑树的高度不会超过2log n。红黑树只比高度平衡的AVL树高了一倍,因此损失的性能并不多。而相对于AVL树,红黑树维护成本更低,因此,性能并不比AVL树差。

所以为什么红黑树如此受欢迎呢? 

AVL树是一种高度平衡的二叉树,查找数据的效率非常高,但是,AVL树为了维持这种高度的平衡,需要付出更多的代价。为了维持平衡性,每次插入、删除数据都要对树中节点的分布做调整,操作复杂、耗时。
红黑树只做到了近似平衡,并没有做到严格定义上的平衡,因此,维护平衡性的成本比AVL树要低,但性能又损失不大。对于工程应用,我们更倾向于维护成本和性能相对折中的红黑树。更加重要的一点是,大部分编程语言提供了封装了红黑树实现的类,我们直接拿来用即可,不需要从零开始实现,大大节省了开发时间。红黑树是一种近似平衡的二叉查找树。 它是为了解决二叉查找树动态数据更新导致的性能退化问题而创造的。红黑树的高度近似于logn,插入、删除和查找操作的时间复杂度都是O(logn)。
 

红黑树节点的定义 

   // 节点的颜色
    enum Color { RED, BLACK };


    // 红黑树节点的定义
    template
    struct RBTreeNode
    {
        RBTreeNode(const T& data = T(),Color color = RED)
            : _pLeft(nullptr), _pRight(nullptr), _pParent(nullptr)
            , _data(data), _color(color)
        {}
        RBTreeNode* _pLeft;   // 节点的左孩子
        RBTreeNode* _pRight;  // 节点的右孩子
        RBTreeNode* _pParent; // 节点的双亲
        T_data;            // 节点的值域
        Color _color;               // 节点的颜色
    };

在插入节点时,我们将节点的默认颜色给成红色的,因为每条路径上黑色节点相同,如果将节点给成黑色的,就会影响每一条路径,将新节点给成红色如果不符合规则,只需要调整这一条或者相邻路径,将新节点给成红色比将新节点给成黑色代价要小得多。

红黑树的插入

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

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

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

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

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

cur节点不一定是新增节点,有可能是调整之后指向的节点。

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

解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

情况二: cur为红,p为红,g为黑,u不存在/u存在且为黑 

u的情况有两种
1.如果u节点不存在,则cur一定是新插入节点,因为如果cur不是新插入节点,则cur和p一定有一个节点的颜色是黑色,就不满足性质∶每条路径黑色节点个数相同。
2.如果u节点存在,则其一定是黑色的,那么cur节点原来的颜色一定是黑色的,现在看到其是红色的原因是因为cur的子树在调整的过程中将cur节点的颜色由黑色改成红色。

解决方式: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

代码实现:

bool Insert(const T& data){if (_root == nullptr){_root = new Node(data);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (data > cur->_data){parent = cur;cur = cur->_right}else if (data < >> cur->_data){parent = cur;cur = cur->_left}else {return false;}}//插入节点cur = new Node(data);cur->_col(RED);if (parent->data < data){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}//控制平衡while (parent && parent->_col == RED){Node* grandfather = parent->_parent;if (parent == grandfather->_left){Node* uncle = parent->_right;//1.uncle存在且为红if (uncle && uncle->_col == RED){//变色+继续向上处理parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else//2.uncle不存在/uncle存在且为黑{//        g//     p//  c//        g//     p//        cif (cur == parent->_left){//右旋RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}if (cur == parent->_right){//先左旋再右旋RotateL(parent);RotateR(grandfather);parent->_col = BLACK;grandfather->_col = RED;}break;}}else // parent == grandfather->_right{Node* uncle = grandfather->_left;if (uncle && uncle->_col == RED){// 变色+继续向上处理parent->_col = uncle->_col = BLACK;grandfather->_col = RED;cur = grandfather;parent = cur->_parent;}else // 2 + 3、uncle不存在/ 存在且为黑{//  g    //     p//        c//  g//     p//  cif (cur == parent->_right){RotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else{RotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;return true;}

 红黑树的验证

红黑树的检测分为两步:

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

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

bool IsBalance(){if (_root && _root->_col == RED){cout << "根节点不是黑色" << endl;return false;}// 最左路径黑色节点数量做基准值int banchmark = 0;Node* left = _root;while (left){if (left->_col == BLACK)++banchmark;left = left->_left;}int blackNum = 0;return _IsBalance(_root, banchmark, blackNum);}bool _IsBalance(Node* root, int banchmark, int blackNum){if (root == nullptr){if (banchmark != blackNum){cout << "存在路径黑色节点的数量不相等" << endl;return false;}return true;}if (root->_col == RED && root->_parent->_col == RED){cout << "出现连续红色节点" << endl;return false;}if (root->_col == BLACK){++blackNum;}return _IsBalance(root->_left, banchmark, blackNum)&& _IsBalance(root->_right, banchmark, blackNum);}

相关内容

热门资讯

贝莱德:美元的世界储备货币地位... 美国资产管理集团贝莱德公司于当地时间6月30日发布2025年第三季度固定收益展望报告。报告称,美元作...
2025海南省中等职业学校教师... 中新网海南新闻6月30日电(张茜翼 黄方舟)温杯洁具、赏茶、投茶、冲泡、出汤、奉茶……30日,202...
南昌新建区启动“同心微光”公益... 6月29日,南昌市新建区 “同心微光” 品牌公益服务项目启动仪式暨 “童心愿” 圆梦活动举行,全区统...
康鹏科技:两股东减持计划实施完... 近日,上海康鹏科技股份有限公司发布了持股5%以上股东权益变动触及1%刻度暨减持股份结果公告。此次公告...
中新健康丨国家医保局:2024... 中新网北京7月1日电(赵方园)7月1日,国家医保局、国家卫生健康委印发的《支持创新药高质量发展的若干...
一汽解放:5年投资回报率负20... 投资者提问:从2020年5月20日公司正式改名一汽解放登陆资本市场,到现在,整整5年多的时间,算上你...
永仁县政务服务“上门办”从“最...   原标题:永仁县政务服务“上门办”从“最多跑一次”到“一次不用跑”  今年以来,永仁县持续深化“放...
夏天怕水果放坏?科学家的新发现... 转自:科普中国每当看到新鲜葡萄渗出酒味,或是芒果表皮浮现黑斑,我们都在见证一场微观世界的“真菌入侵”...
电解铝:上半年关税博弈铝价韧性... 【导语】2025年上半年电解铝市场基本面运行稳健,虽受到对等关税影响,需求端面临一定出口压力,但总体...
好上好:公司不存在应披露而未披... 格隆汇7月1日|好上好(001298.SZ)公告称,公司股票于2025年6月27日、6月30日、7月...