红黑树的学习

2024-08-21 14:04
文章标签 学习 红黑树

本文主要是介绍红黑树的学习,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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

1.2 红黑树的性质

1. 每个结点不是红色就是黑色
2. 根节点是黑色的 
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点 
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)
1.3 红黑树的定义
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> _data):_kv(_data), left(nullptr), right(nullptr), parent(nullptr){}
};template<class K,class V>
class RBTree
{typedef RBTreeNode<K,V> Node;
private:
Node* root;
}
1.4 红黑树结构
为了后续实现关联式容器简单,红黑树的实现中增加一个头结点,因为跟节点必须为黑色,为了
与根节点进行区分,将头结点给成黑色,并且让头结点的 pParent 域指向红黑树的根节点,pLeft
域指向红黑树中最小的节点,_pRight域指向红黑树中最大的节点
1.5 红黑树的插入
<1>: 我们默认插入的时候 都是红色结点 ,这是为什么?如果每次插入是黑色结点,我都得协调每条路径的黑色结点,如果是红色,我只需要考虑,它的父亲是不是红色结点,在进行调色
<2>. 如果父亲结点是红色,那么我们有两种情况
第一种:叔叔(父亲的兄弟结点,也就是父亲的父亲,它的除了父亲的孩子)存在且为红色结点,那么我们就需要把叔叔和父亲一起调成黑色,接着再往上调整父亲的父亲的结点颜色
第二种  爷爷是黑色的  叔叔 不存在 或者 是黑色结点 那么我们就要进行旋转了,旋转之后进行调整颜色
同样我们这里的旋转也分为单旋转还是双旋
首先介绍第一种情况
cur为新插入的结点,然后父亲和叔叔都是红色,我们把他两变成黑色,然后g结点改成红色,再把g结点给cur赋值,再进行调色
!第二种情况叔叔是黑色的只有在第一种情况往上调整的时候才会出现,也就是说直接插入是不会存在这种情况的

  假设cur是新插入的结点,那么第二层,一个黑的一个红的,都不符合简单路径黑色结点数量一致。

然后我们这时候就要旋转了,这时候一眼就能看出来,右旋转,g 结点变红,p成根,变成黑色,旋转就不用再往上改颜色了。

我们来举个双旋的例子,其实有了AVL树的学习,这些一眼就能看出来怎么旋转

我们这个还有略微不同,AVL树是在旋转里面就进行了平衡因子的修正,我们呢是在旋转完之后,我们再进行调色。总结一下:情况二 单旋是祖孙三代在同一条线上,双旋是祖孙三带两个在一条线上。所以我们根据是从上到左下角的线呢,还是从上到右下角的线呢。进行右旋或者左旋,左右旋或者是右左旋(这几个顺序是一以对应的,或者前面的对前面,或者后面的对后面)

bool insert(const pair<K, V>& kv)
{if (root == nullptr){root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->right;}else{cout << "已经重复了" << endl;return false;}}cur = new Node(kv);cur->col = Red;if (parent->_kv.first > kv.first){parent->left = cur;}else{parent->right = cur;}cur->parent = parent;while (parent && parent->col == Red){Node* grandfather = parent->parent;Node* uncle = nullptr;//  g//u   p//      cif (parent == grandfather->right){uncle = grandfather->left;if (uncle && uncle->col == Red)//叔叔是红色的 ,就改变颜色{parent->col = uncle->col = Black;grandfather->col = Red;cur = grandfather;//改完色之后 更新成爷爷为插入的结点了parent = cur->parent;}else//uncle 为黑色 或者 不存在 就看单旋还是双旋{//统一一根线是单旋 if (cur == parent->right){grandfather->col = Red;parent->col = Black;RotateL(grandfather);	 }//   g// u   p//   celse{RotateR(parent);RotateL(grandfather);cur->col = Black;grandfather->col = Red;}break;}}else{//   g//  p  u//cuncle = grandfather->right;if (uncle && uncle->col == Red)//叔叔是红色的 ,就改变颜色{parent->col = uncle->col = Black;grandfather->col = Red;cur = grandfather;//改完色之后 更新成爷爷为插入的结点了parent = cur->parent;}else//uncle 为黑色 或者 不存在 就看单旋还是双旋{//统一一根线是单旋 if (cur == parent->left){grandfather->col = Red;parent->col = Black;RotateR(grandfather);}//   g// p   u//   celse{RotateL(parent);RotateR(grandfather);cur->col = Black;grandfather->col = Red;}break;}}}root->col = Black;return true;}
void RotateL(Node* parent)
{Node* subR = parent->right;Node* subRL = subR->left;parent->right = subRL;if (subRL)subRL->parent = parent;Node* PParent = parent->parent;subR->left = parent;parent->parent = subR;if (PParent){subR->parent = PParent;if (PParent->left == parent)PParent->left = subR;elsePParent->right = subR;}else{subR->parent = nullptr;root = subR;}}void RotateR(Node* parent)
{Node* subL = parent->left;Node* subLR = subL->right;parent->left = subLR;if (subLR)subLR->parent = parent;Node* PParent = parent->parent;subL->right = parent;parent->parent = subL;if (PParent == nullptr){root = subL;}else{if (PParent->right == parent)PParent->right = subL;elsePParent->left = subL;}subL->parent = PParent;}

1.6红黑树的验证 红黑树的检测分为两步:

1. 检测其是否满足二叉搜索树(中序遍历是否为有序序列)
2. 检测其是否满足红黑树的性质
	bool _IsBalance(Node* _root){if (_root == nullptr)return true;if (_root->col == Red)return false;Node* cur = _root;int  count = 0;while (cur){if (cur->col==Black){count++;}cur = cur->left;}return check(count, 0, _root);}bool check(int count, int num, Node* _root){if (_root == nullptr){if (count != num){cout << "路径长度不一致" << endl;cout << count << "::" << num << endl;return false;}return true;}if (_root->col == Red){if (_root->parent->col == Red){cout<<"连续红色"<<endl;return false;}}if (_root->col == Black){num++;}return check(count, num, _root->left) && check(count, num, _root->right);}

我们在isbalance 函数里面算出一条路径的黑色结点数量(对比值),在check函数里面检查所有的路径是不是都是一样的结点,我们在是空的时候,算是遍历完该条路径,所以在那时候比较黑色结点数量与对比值。

在计算路径黑色结点个数的时候,我们可以检查到红结点的时候,判断它的父亲是不是也是红色,如果从父亲判断孩子的话,有两个孩子,还需要判断空指针问题,不如判断父亲的颜色,因为根是黑色的,不用担心他被访问父亲。

这篇关于红黑树的学习的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1093363

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件