当前位置: 首页 > news >正文

C++红黑树 - 教程

目录

1.红黑树的概念

2.红黑树的性质

3.红黑树的节点定义

4.红黑树的插入操作

4.1按照二叉搜索数的规则插入一个新的节点

4.2根据红黑树的规则对该树进行调整

4.3插入的代码

5.红黑树的验证

6.红黑树与AVL树的比较


1.红黑树的概念

红黑树是一种二叉搜索树,在每一个节点上增加了一个存储位用来表示该节点的颜色,可以是红色也可以是黑色。通过对任何一条从根到叶子的路径上各个节点着色方式的限制,红黑树确保没有一条路径会比其他路径长出两倍,故它是接近平衡

2.红黑树的性质

  1. 每个节点不是黑色就是红色
  2. 根节点是黑色
  3. 如果一个节点是红色,则它的两个孩子节点都是黑色(整棵树中父子节点之间不会出现连续的红色节点)
  4. 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,黑色节点的数量相同(每条路径上有相同数量的黑色节点)
  5. 每个叶子节点都是黑色的(这里的叶子节点指的是最后的空节点)

路径:从根节点开始,到该树的叶子节点(最后的空节点)结束

一棵红黑树中,最短的路径即所有节点都是黑色的,而最长的路径是红黑节点交替的,因此该树所有路径的长度在[h,2h]之间(最长和最短路径不一定存在)

3.红黑树的节点定义

enum Color
{Red,Black
};
template
struct RBTreeNode
{RBTreeNode(const T& val = T(),Color col = Red) //这里新插入的节点我们默认为红色:_parent(nullptr),_left(nullptr),_right(nullptr),_val(val),_col(col){ }RBTreeNode* _parent;RBTreeNode* _left;RBTreeNode* _right;T _val;Color _col;
};

新插入的节点我们默认为红色的原因:如果新插入的节点是黑色,就一定会破坏红黑树的第4条性质,这就影响到了整棵树;但是如果新插入的节点是红色,有可能会破坏红黑树的第3条性质,这仅仅影响到这一条路径

4.红黑树的插入操作

4.1按照二叉搜索数的规则插入一个新的节点

if (_root == nullptr)
{_root = new Node(val);_root->_col = Black;return true;
}
else
{Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (val > cur->_val){cur = cur->_right;}else if (val < cur->_val){cur = cur->_left;}else{return false;}}cur = new Node(val);if (cur->_val > parent->_val){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;
}

4.2根据红黑树的规则对该树进行调整

首先我们需要去判断新插入的节点有没有破坏红黑树的性质。首先去看新插入节点的父节点,如果父节点是黑色,则说明没有违反红黑树的任何性质,不需要进行调整;如果其父节点是红色,就破坏了红黑树的第3条性质,需要对该树进行调整,需要分情况讨论:

cur为新插入的节点,p是其父节点,g是p的父节点,u是p的兄弟节点

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

这种情况我们只需要将g的颜色变为红色,p和u的颜色变为红色即可

注:如果g为根节点,需要将g的颜色再变为黑色;如果g不是根节点,这仅仅是一棵子树,需要继续向上检查进行调整

情况2:cur为红,p为红,g为黑,u不存在或u存在且为黑(单旋+变色解决)

1.如果u不存在,则说明a、b、c、d、e这五棵子树都不存在,这是因为如果c存在的话,则说明c里面存在黑色节点,违反了红黑树第4条性质。g为黑色,p为红色,cur如果不是新插入的节点的话一定是黑色,但如果cur是黑色同样违反红黑树第4条性质,因此cur是新插入的节点

2.如果u存在且为黑色,则说明cur原本的颜色是黑色,由于a或b子树的调整变为了红色

上述两种情况的解决办法:如果p是g的左孩子,cur是p的左孩子,则通过右单旋进行调整;如果p是g的右孩子,cur是p的右孩子,则通过左单旋进行调整。最后将p变为黑色,g变为红色。由于p是黑色,并没有出现连续的红色节点,循环终止

情况3:cur为红,p为红,g为黑,u不存在或u存在且为黑(双旋+变色解决)

这种情况同样是用旋转+变色进行解决,但是用的是双旋。

上图中,首先以p为中心进行左旋,旋转结束后的红黑树与情况2相同,后续步骤可以看情况2

解决方法:如果p为g左孩子,cur为p右孩子,则针对p进行左旋,后续与情况2一致;如果p为g右孩子,cur为p左孩子,则针对p进行右旋,后续与情况2一致

4.3插入的代码

template
class RBTree
{typedef RBTreeNode Node;
public:bool insert(const T& val){if (_root == nullptr){_root = new Node(val);_root->_col = Black;return true;}else{Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (val > cur->_val){cur = cur->_right;}else if (val < cur->_val){cur = cur->_left;}else{return false;}}cur = new Node(val);if (cur->_val > parent->_val){parent->_right = cur;}else{parent->_left = cur;}cur->_parent = parent;while (parent && parent->_col == Red){Node* grandparent = parent->_parent;if (grandparent->_left == parent){Node* uncle = grandparent->_right;if (uncle && uncle->_col == Red){grandparent->_col = Red;parent->_col = uncle->_col = Black;//继续向上检查cur = grandparent;parent = cur->_parent;}else //(uncle == nullptr || uncle->_col == Black){//cur是parent的左孩子,单旋调整if (cur == parent->_left){RotateR(grandparent);parent->_col = Black;grandparent->_col = Red;}else //cur是parent的右孩子,双旋调整{RotateL(parent);RotateR(grandparent);cur->_col = Black;grandparent->_col = Red;}break;}}else{Node* uncle = grandparent->_left;if (uncle && uncle->_col == Red){grandparent->_col = Red;parent->_col = uncle->_col = Black;cur = grandparent;parent = cur->_parent;}else{if (cur == parent->_right){RotateL(grandparent);parent->_col = Black;grandparent->_col = Red;}else{RotateR(parent);RotateL(grandparent);cur->_col = Black;grandparent->_col = Red;}break;}}}_root->_col = Black;return true;}}
private:void RotateR(Node* parent){Node* subl = parent->_left;Node* sublr = subl->_right;Node* pparent = parent->_parent;parent->_left = sublr;if (sublr)sublr->_parent = parent;subl->_right = parent;parent->_parent = subl;if (_root == parent){_root = subl;subl->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = subl;}else{pparent->_right = subl;}subl->_parent = pparent;}}void RotateL(Node* parent){Node* subr = parent->_right;Node* subrl = subr->_left;parent->_right = subrl;subr->_left = parent;Node* pparent = parent->_parent;parent->_parent = subr;if (subrl)subrl->_parent = parent;if (_root == parent){_root = subr;subr->_parent = nullptr;}else{if (pparent->_left == parent){pparent->_left = subr;}else{pparent->_right = subr;}subr->_parent = pparent;}}Node* _root = nullptr;
};

5.红黑树的验证

对其进行检查主要是检查每条路径上的黑色节点数相同和没有连续的红色节点

bool CheckColour(Node* root, int blacknum, int benchmark)
{if (root == nullptr){if (blacknum != benchmark)return false;return true;}if (root->_col == Black){++blacknum;}if (root->_col == Red && root->_parent && root->_parent->_col == Red) //检查是否出现连续的红色节点{cout << root->_val << "出现连续红色节点" << endl;return false;}return CheckColour(root->_left, blacknum, benchmark)&& CheckColour(root->_right, blacknum, benchmark);
}
bool _IsBalance(Node* root)
{if (root == nullptr)return true;if (root->_col != Black) //根节点必须是黑色{return false;}//设立一个基准值用来存储该树中其中一条路径黑色节点的数量,再与其他路径的黑色节点树比较,只要有其中一条与其不同,就说明该树有问题。不需要管基准值中存储的数据是否正确int benchmark = 0; //基准值Node* cur = _root;while (cur){if (cur->_col == Black)++benchmark;cur = cur->_left;}return CheckColour(root, 0, benchmark);
}
bool IsBalance()
{return _IsBalance(_root);
}

6.红黑树与AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是\log _{2}N,红黑树不追求绝对的平衡,它是相对平衡,其只需要保证最长路径不超过最短路径的二倍即可,与AVL树相比减少了插入和旋转次数,所以红黑树的性能比AVL树更好,且红黑树的实现更为简单。

http://www.jsqmd.com/news/304750/

相关文章:

  • 2026年 工业超声波清洗机厂家推荐排行榜,单槽/实验室/全自动/投入式/网纹辊/眼镜首饰/除油除锈清洗机及振子振板配件选购指南
  • 2026 年 1 月原油脱水仪/破乳仪厂家推荐排行榜:高效分离、精准破乳,油田采出液处理核心设备源头实力解析
  • 火语言 RPA:英数图形验证码自动化处理案例
  • 如何绑定自己的域名生成专属短链接
  • 【趋势】AI编程已成标配,大模型开发者薪资翻倍,小白如何快速上车?
  • 2026年 链条厂家推荐排行榜:精密滚子/非标输送/多板/钢厂专用链条,实力源头工厂技术解析与选购指南
  • 一次 IDE Agent 死循环问题的架构复盘 - 实践
  • 总结:短期 “稳”,长期 “变”
  • 对资本市场:短期催化相关板块,中长期聚焦 “国产替代主线”
  • 直接扩频通信系统链路仿真实现指南
  • 对中国市场:短期信心提振,
  • 从 “卖芯片” 转向 “稳生态 + 合规落地”
  • 产业链影响:上游受益,下游分化,本土配套加速
  • 西部生态建设新范式:科技赋能重塑发展底色
  • 本地部署开源数字人模型简介
  • 学霸同款2026 AI论文软件TOP9:毕业论文写作全攻略
  • 灵感枯竭?别慌!试试AI脑洞速成法,让你的创意火花Duang Duang冒
  • 听说有人想用智能算法暴打旅行商?这事我熟啊!当年被TSP按在地上摩擦的经历还历历在目。今天咱们拿遗传算法开刀,手把手教你造个能自己找最优路线的AI
  • 【毕业设计】基于springboot的高校学生心理健康管理系统(源码+文档+远程调试,全bao定制等)
  • 不锈钢紧固件与碳钢紧固件的区别与应用场景
  • 冷镦工艺如何重塑紧固件制造
  • 从百度贴吧的数字遗址到短视频多巴胺魔幻丛林,普罗大众认知平面化困境正在加速形成和固化?
  • 2026年混合机厂家推荐排行榜:二维/三维/双锥/槽型/双螺杆螺旋/V型/卧式螺带/高速/无重力双轴桨叶混合机,高效混合与稳定性能深度解析
  • 2026年 北京公司注册服务TOP5权威推荐:执照办理、地址挂靠、流程材料一站式解决方案深度解析
  • 鲜花 1.26
  • 一次性补贴1000-3120元/人|2026人工智能训练师应该怎么报考?
  • 救命神器2026 TOP8 AI论文网站:MBA开题报告全测评
  • 【计算机毕业设计案例】基于springboot+vue的服务商后台管理系统(程序+文档+讲解+定制)
  • 【计算机毕业设计案例】基于springboot的二手手机销售系统基于SpringBoot+Vue的二手手机交易平台(程序+文档+讲解+定制)
  • 2026年静音门窗/系统门窗/断桥铝门窗/隔音门窗厂家推荐排行榜:专业实力与匠心工艺深度解析