【C++】红黑树插入操作实现以及验证红黑树是否正确

文章目录

  • 前言
  • 一、红黑树的插入操作
    • 1.红黑树结点的定义
    • 2.红黑树的插入
      • 1.uncle存在且为红
      • 2.uncle不存在
      • 3.uncle存在且为黑
    • 3.完整代码
  • 二、是否为红黑树的验证
    • 1.IsBlance函数
    • 2.CheckColor函数
  • 三、红黑树与AVL树的比较


前言

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

红黑树的性质:

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点 (每条路径上的黑色结点数量相同)
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
    在这里插入图片描述
    最短路径:全部都是黑节点的路径。
    最长路径:一黑一红相间的路径

一、红黑树的插入操作

1.红黑树结点的定义

enum Color {RED,BLACK
};
template<class K,class V>
struct RBTreeNode {RBTreeNode* _left;RBTreeNode* _right;RBTreeNode* _parent;pair<K, V>_kv;Color _col;//颜色RBTreeNode(const pair<K,V>&kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_col(RED)//结点默认给成红色是为了方便后续的插入//因为默认为黑色的话还需要考虑所有路径上黑色结点数量是否相同//太麻烦了{}
};

2.红黑树的插入

插入分为一下三种情况,因为我们插入的结点默认为红色,而红黑树定义中指出不能出现连续的两个红色结点,为了维持红黑树,我们需要对一些结点的颜色进行改变有时还需要旋转改变树的形状,至于有关旋转的函数Rotate,我已经在之前AVL树的模拟实现中详细说明了,这里就不多在赘述了【C++】AVL树的插入操作实现以及验证是否正确(带平衡因子),有需要的可以去看一下。

1.uncle存在且为红

这种情况就不需要考虑旋转了
在这里插入图片描述
在这里插入图片描述

2.uncle不存在

在这里插入图片描述

3.uncle存在且为黑

在这里插入图片描述
在这里插入图片描述

总结:
红黑树插入关键看uncle
1.uncle存在且为红,变色(uncle与parent变黑色,grandfather变红色),之后继续向上处理
2.uncle不存在或者uncle存在且为黑,旋转加变色,之后break
3.小规律:grandfather在这个过程中要不本来就为红色,要不就变成红色

3.完整代码

template<class K,class V>
class RBTree {typedef RBTreeNode<K,V> Node;
public:bool Insert(const pair<K, V>& kv) {if (_root == nullptr) {//根节点必须为黑色_root = new Node(kv);_root->_col = BLACK;return true;}Node* cur = _root;Node* parent = nullptr;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;if (parent = grandfather->_left) {Node* uncle = grandfather->_right;if (uncle && uncle->_col == RED) {//uncle存在且为红parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续向上更新cur = grandfather;parent = cur->_parent;}else {//uncle不存在或者uncle为黑if (cur == parent->_left) {//     g//   p// cRotateR(grandfather);grandfather->_col = RED;parent->_col = BLACK;}else {//     g//   p//		cRotateL(parent);RotateR(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}else {// parent == grandfather->_rightNode* uncle = grandfather->_right;if (uncle && uncle->_col == RED) {//uncle存在且为红parent->_col = uncle->_col = BLACK;grandfather->_col = RED;//继续向上更新cur = grandfather;parent = cur->_parent;}else {//uncle不存在或者uncle为黑if (cur == parent->_right) {// g//	  p//       cRotateL(grandfather);parent->_col = BLACK;grandfather->_col = RED;}else {// g//	  p// cRotateR(parent);RotateL(grandfather);cur->_col = BLACK;grandfather->_col = RED;}break;}}}_root->_col = BLACK;//根节点必须为黑色return true;}void RotateL(Node* parent) {//左旋Node* cur = parent->_right;Node* curleft = cur->_left;parent->_right = curleft;if (curleft) {curleft->_parent = parent;}cur->_left = parent;Node* ppnode = parent->_parent;if (ppnode == nullptr) {_root = cur;cur->_parent = nullptr;}else {if (ppnode->_left = parent) {ppnode->_left = cur;}else {ppnode->_right = cur;}cur->_parent = ppnode;}}void RotateR(Node* parent) {//右旋Node* cur = parent->_left;Node* curright = cur->_right;parent->_left = curright;if (curright) {curright->_parent = parent;}cur->_right = parent;Node* ppnode = parent->_parent;parent->_parent = cur;if (ppnode == nullptr) {_root = cur;cur->_parent = nullptr;}else {if (ppnode->_left == parent) {ppnode->_left = cur;}else {ppnode->_right = cur;}cur->_parent = ppnode;}}
};

二、是否为红黑树的验证

1.IsBlance函数

bool IsBalance() {return IsBalance(_root);}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 CheckColor(root, 0, benchmark);}

2.CheckColor函数

bool CheckColor(Node* root, int blacknum, int benchmark) {if (root == nullptr) {//root为空说明已经数完了一条路径的黑色结点//与原先数的最左的黑色节点数进行比较if (blacknum != benchmark) {return false;}return true;}if (root->_col == BLACK) {blacknum++;//当前路径黑色结点树++}if (root->_col == RED && root->_parent && root->_parent->_col == RED) {cout << root->_kv.first << "出现连续红色节点" << endl;//判断是否出现连续的红色结点return false;}//递归式对左右子树分别检验return CheckColor(root->_left, blacknum, benchmark) && CheckColor(root->_right, blacknum, benchmark);}

三、红黑树与AVL树的比较

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/110007.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

了解消息中间件的基础知识

为什么要使用消息中间件&#xff1f; 解耦&#xff1a;消息中间件可以使不同的应用程序通过解耦的方式进行通信&#xff0c;减少系统间的依赖关系提供异步通信&#xff1a;消息中间件可以实现异步消息传递&#xff0c;提高系统的响应性能。流量削峰&#xff1a;消息中间件可以…

Rust :与C交互

rust调用C端的库函数&#xff0c;有很多方法。今天介绍通过cc库的方式&#xff0c;实现rust调用c端库函数。 1、相关准备&#xff1a; 在ffi目录下&#xff0c;创建了c_part和rust_ffi文件夹。 c_part下放了ctools.c文件&#xff0c;里面有一些库函数&#xff0c;需要让rust调…

四川百幕晟科技:提升店铺质量方法是什么?

抖店是抖音旗下的移动电子商务平台&#xff0c;为商家提供在线销售和促销的机会。在抖店&#xff0c;经验值是商家评价和信誉的重要指标之一。反映了平台上商户的服务质量和用户满意度。那么&#xff0c;如何查看自己在抖店手机上的体验分数呢&#xff1f; 1、如何查看抖店手机…

【数据结构】堆排序详解

文章目录 一、堆排序思想二、向上调整建堆排序三、向下调整建堆排序四、总结 对于什么是堆&#xff0c;堆的概念分类以及堆的向上和向下两种调整算法可见&#xff1a; 堆的创建 一、堆排序思想 int a[] { 2,3,5,7,4,6 };对于这样一个数组来说&#xff0c;要想要用堆排序对它…

脚本:用python实现五子棋

文章目录 1. 语言2. 效果3. 脚本4. 解读5. FutureReference 1. 语言 Python 无环境配置、无库安装。 2. 效果 以第一回合为例 玩家X 玩家0 3. 脚本 class GomokuGame:def __init__(self, board_size15):self.board_size board_sizeself.board [[ for _ in range(board_…

(高阶)Redis 7 第12讲 数据双写一致性 经验篇

面试题 /问题1涉及到redis缓存和数据库双存储双写,出现的数据一致性问题,如何解决2双写一致性,先动缓存Redis还是数据库?3延时双删做过吗,有哪些问题?4微服务查询Redis无数据,数据库有数据,为保证数据双写一致性回写Redis需要注意什么?双检加锁策略了解吗?如何避免缓存…

操作系统运行环境

目录 操作系统运行环境&#xff08;1&#xff09; 第一节 一、处理器的构成与基本工作方式 二、特权和非特权指令 三、处理器的工作状态 四、程序状态字 第二节、计算机系统硬件部件 一、存储系统 二、I/O部件&#xff1a;1.I/O结构&#xff0c;2.通道&#xff0c;3.D…

CSS 四中方法实现水平 垂直居中

CSS 四中方法实现水平 垂直居中 效果 结构 <div class"a"><div class"b"></div></div>样式 方法一 .a {width: 500px;height: 500px;margin: 50px auto;background-color: crimson;// 核心代码display: flex;justify-content: …

HTML整站规划与规范

文章目录 命名规则命名命名书写 包含样式规范样式重置样式引入页面结构页面宽度页面高度与背景页面设计 网址图标 命名规则 命名 根据每块元素的主题、功能、页面上的位置命名&#xff0c;便于后期更改与维护。 另外&#xff1a;如果所有样式放在同一文件下&#xff0c;可以给…

idea项目配置三大步

场景&#xff1a; 使用 idea 打开一个新项目的时候&#xff0c;想让项目迅速跑起来&#xff0c; 其实只需要下面简单三步&#xff1a; 1. 首先&#xff0c;配maven 2. 其次&#xff0c;配置 jdk 这里配置 project 就行了&#xff0c;不用管Modules中的配置。 3. 最后&#…

ubuntu 22.04运行opencv4的c++程序遇到的问题

摘要&#xff1a;本文介绍一下在ubuntu系统中&#xff0c;运行一个最简单的opencv4程序都出问题的解决方法&#xff0c;并对其基本原理作简单阐述。解决问题的方法有很多&#xff0c;本文只提供其中一种。 opencv版本是4.2.0&#xff0c;ubuntu版本是20.04 查询opencv版本的指…

如何让两台手机相互远程控制?

你的两台手机是什么系统的&#xff1f;如果你的两台手机都是安卓系统&#xff0c;而且都是安卓7.0及以上版本的系统&#xff0c;那么恭喜你&#xff0c;这两台手机可以相互远程控制&#xff01; 你可以利用两个软件实现将两台手机相互远程控制的想法。为了避免混淆&#xff0c…