【C++高阶(四)】红黑树深度剖析--手撕红黑树!

这篇具有很好参考价值的文章主要介绍了【C++高阶(四)】红黑树深度剖析--手撕红黑树!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++
  🔝🔝


【C++高阶(四)】红黑树深度剖析--手撕红黑树!,C++从入门到精通,c++,开发语言,数据结构

1. 前言

如果说发明AVL树的人是天才,那么
发明红黑树的人可以称为天才中的
精英!为什么AVL树这么强大但是没啥
人用呢?就是因为红黑树比你还好!

本章重点:

本篇文章着重讲解红黑树的概念以及
性质,以及为了维护红黑树这种性质而
做的限制条件.最后模拟实现红黑树的
插入,带大家熟悉变色和旋转规则!


2. 红黑树的概念以及性质

红黑树的概念:

  • 首先红黑树是一颗二叉搜索树
  • 每个节点都有颜色,红色或黑色
  • 最长路径最多是最短路径的二倍

【C++高阶(四)】红黑树深度剖析--手撕红黑树!,C++从入门到精通,c++,开发语言,数据结构

红黑树的性质:

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的
    则它的两个孩子结点是黑色的
  4. 每条路径上的黑色节点数相同
  5. 每个叶子结点都是黑色的
    (此处的叶子结点指的是空结点)
为啥满足了以上性质的红黑树就一定
能做到最长路径最多是最短路径的二倍?
下面我画一个极限情况来分析一下!

【C++高阶(四)】红黑树深度剖析--手撕红黑树!,C++从入门到精通,c++,开发语言,数据结构


3. 红黑树为什么更实用?

现在将AVL数和红黑树做一个对比:

  • AVL树阐析:

AVL树是一颗高度平衡二叉树,
它的高度差不能大于1,所以AVL
树的查找是妥妥的O(logn),但是
由于AVL树严格的标准,使得在使用
AVL树时会经常旋转,反而增加了时间!

  • 红黑树阐析:

红黑树是一颗接近平衡的二叉树
它最长路径最多是最短路径的二倍
所以查找的效率是:logn~2logn,
然而2
logn和logn是一个量级的,
并且红黑树的规则没有这么严格,
不会涉及到更多旋转和变色!

综上所述,红黑树的效率虽然比
AVL树差一点,但是总体来说红黑树胜!

4. 红黑树模拟实现代码框架

首先,每个节点都要存一个颜色,
这里我们使用枚举enum来实现
并且和AVL一样也是三叉链!
请看代码:

enum Colour
{
	RED,
    BLACK
};
template<class K,class V>
struct RBTreeNode
{
	RBTreeNode(const pair<K, V>& kv)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		,_col(RED)
	{}
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv; 
	Colour _col;
};

template<class K, class V>
struct RBTree
{
typedef RBTreeNode<K, V> Node;
private:
	Node* _root = nullptr;
};

有了代码框架后,现在来看看插入


5. 红黑树的插入操作初步分析

和AVL树很相似,红黑树的插入
也是分为两步走:

  1. 按照二叉搜索树的规则插入值
  2. 插入后根据颜色或高度做旋转或变色

众所周知啊,第一步很简单
甚至可以将之前的代码抄过来:

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);
	if (parent->_kv.first < kv.first)
		parent->_right = cur;
	else
		parent->_left = cur;
	//此时new出来的节点的parent还指向空
	cur->_parent = parent;
	///前面的过程和AVL树一致
}

走到这步后,有个问题,新插入的节点
是选择插入红色还是黑色?

对于这个问题,我们要思考两个点,
一是如果插入的是黑色节点,我们
可能会打破哪个规则?如果是插入
红色节点又可能会打破哪个规则?

  • 插入黑色节点,打破规则四,很难办
    因为每个路径检查起来很难!

  • 插入红色节点,打破规则三,比打破
    四要好一些,因为只用看父亲是否为红

综上所述,插入红色更优!
换句话说,你犯错肯定宁愿犯轻一点
的错误被妈妈打一顿,也不愿意犯很重
的错直接被家族除名了对吧[doge]

6. 红黑树的插入操作详解(一)

如果插入的节点的父亲是黑色节点,
那么正是我们想看见的,不用管它了!

那么如果插入的节点的父亲是红色呢?
很明显,这违反了规则三,有连续的红色
节点,所以此时需要做处理了!

先来看一个最简单的情况:

【C++高阶(四)】红黑树深度剖析--手撕红黑树!,C++从入门到精通,c++,开发语言,数据结构

其实红黑树插入节点后的变色和
旋转规则主要是看叔叔,叔叔的情况
不同,那么对应的处理手段就不同,这里
只通过简单变色手段就可以满足规则了!
并且在上图中,将爷爷变成红色后可能会
出现问题,因为爷爷的父亲不知道是红色
还是黑色,所以要不断向上做判断

若不向上更新,可能会有这种情况:

【C++高阶(四)】红黑树深度剖析--手撕红黑树!,C++从入门到精通,c++,开发语言,数据结构


7. 红黑树的插入操作详解(二)

当讲解完最简单的情况后,还剩下两种
情况,这两种情况内部又可细分出几种
情况,请同学们耐心学习!

情况二:cur为红.p为红.g为黑.u不存在/为黑
(并且cur和p都是左或右)

【C++高阶(四)】红黑树深度剖析--手撕红黑树!,C++从入门到精通,c++,开发语言,数据结构
【C++高阶(四)】红黑树深度剖析--手撕红黑树!,C++从入门到精通,c++,开发语言,数据结构

p为g的左孩子,cur为p的左孩子,则右单旋
p为g的右孩子,cur为p的右孩子,则左单旋
p,g变色—p变黑,g变红

情况三:cur为红.p为红.g为黑.u不存在/为黑
(并且若p是g的左,cur就是p的右)

【C++高阶(四)】红黑树深度剖析--手撕红黑树!,C++从入门到精通,c++,开发语言,数据结构

p为g的左孩子,cur为p的右孩子,则做左单旋
p为g的右孩子,cur为p的左孩子,则做右单旋
则转换成了情况二

至此,红黑树的插入的所有情况都
讲解完毕,接下来就是代码实现了!


8. 红黑树的插入代码实现

在整个大情况分类中,可以归为两类
一是叔叔为红色,二是叔叔为黑色或者
叔叔不存在,我们围绕着这两个大方向写!

//走到这一步后,就已经找到cur和parent了!
while (parent && parent->_col == RED)//当parent为黑就不用往上更新了
{
	if (parent == _root)
	{
		_root->_col = BLACK;
		break;
	}
	Node* grandf = parent->_parent;
	assert(grandf);
	assert(grandf->_col == BLACK);
	Node* uncle = nullptr;
	if (parent == grandf->_left)//判断叔叔在par的左还是右
		uncle = grandf->_right;
	else uncle = grandf->_left;
	if (uncle == nullptr || uncle->_col == BLACK)//uncle为空或为黑有四种情况来变色+旋转
	{
		if (parent == grandf->_left && cur == parent->_left)//左左->右旋+变色
		{
			RotateR(grandf);
			parent->_col = BLACK;
			grandf->_col = RED;
			break;
		}
		else if (parent == grandf->_right && cur == parent->_right)//右右->左旋+变色
		{
			RotateL(grandf);
			parent->_col = BLACK;
			grandf->_col = RED;
			break;
		}
		else if (parent == grandf->_left && cur == parent->_right)//左右->先左旋再右旋再变色
		{
			RotateL(parent);
			RotateR(grandf);
			cur->_col = BLACK;
			grandf->_col = RED;
			break;
		}
		else if (parent == grandf->_right && cur == parent->_left)//右左->先右旋再左旋再变色
		{
			RotateR(parent);
			RotateL(grandf);
			cur->_col = BLACK;
			grandf->_col = RED;
			break;
		}
	}
	else if (uncle && uncle->_col == RED)//叔叔为红,直接变色,不旋转
	{
		parent->_col = BLACK;
		uncle->_col = BLACK;
		grandf->_col = RED;
		cur = grandf;
		parent = cur->_parent;//将parent更新后往上传!
	}
	_root->_col = BLACK;
}

可以发现一个问题,只要是叔叔的颜色
是黑色或叔叔不存在的情况下,执行完
旋转+变色后都直接break了,这是因为
在这种情况下,父亲节点都被变成了黑色,
也就没必要继续往上了!并且在红黑树的
左旋和右旋中,代码其实和AVL树的旋转是
一模一样的,所以直接copy一份就行了!

若你不清楚旋转的代码,请看这篇文章:

AVL树模拟实现!


9. 总结以及拓展

AVL树和红黑树的代码实现都只讲解
了插入操作,因为删除操作太复杂了,
并且就算实现了删除操作也没有太大
的实际意义,所以只需要了解插入即可!

并不是需要你真正的会手撕!

拓展阅读:

红黑树的删除图解文章来源地址https://www.toymoban.com/news/detail-754598.html


🔎 下期预告:哈希表,哈希桶 🔍

到了这里,关于【C++高阶(四)】红黑树深度剖析--手撕红黑树!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 手撕红黑树

    由于AVL对于平衡的要求过于严格,这就导致了AVL的调整操作会被大量的进行,别看单词的时间消耗短,由于AVL树对于平衡要求的苛刻,这就会积累大量的旋转操作,这一累加起来就是不小的时间消耗; 为了减少AVL树的旋转操作,红黑树不就诞生了! 红黑树:红黑树不是一颗严

    2024年02月04日
    浏览(35)
  • 【手撕红黑树】

    相信很多人初学者听到了红黑树后心中不免有些心慌,那你看到了这篇文章后相信会有所收获,我其实刚开始也是对红黑树抱着一种害怕甚至是恐惧,但是在老师的帮助下也终于慢慢的不在恐惧了,你想知道为什么的话就继续往下看吧。(注意本篇博客只讲解了红黑树的插入

    2024年02月05日
    浏览(25)
  • 史上最详细的红黑树讲解(一篇文章教你手撕红黑树)

           🔥🔥 欢迎来到小林的博客!!       🛰️博客主页:✈️小林爱敲代码       🛰️博客专栏:✈️数据结构与算法       🛰️欢迎关注:👍点赞🙌收藏✍️留言       今天给大家讲解红黑树,和AVL树一样,这章暂且不讲删除。

    2024年01月16日
    浏览(32)
  • 红黑树深入剖析【C++】

    目录 一、红黑树概念  二、红黑树节点结构设计 三、插入操作  处理情况1  处理情况2 处理情况3  插入总结:  四、插入操作源码 五、红黑树验证  红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是 Red 或Black。 通过对任何一条从根到叶

    2024年02月15日
    浏览(24)
  • 【高阶数据结构】红黑树 {概念及性质;红黑树的结构;红黑树的实现;红黑树插入操作详细解释;红黑树的验证}

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

    2024年02月09日
    浏览(39)
  • 【高阶数据结构】红黑树详解

    这篇文章我们再来学习一种平衡搜索二叉树—— 红黑树 红黑树和AVL树都是常见的自平衡二叉搜索树,它们都可以用于高效地支持插入、删除和查找等操作。虽然它们都能够保持树的平衡性,但在不同的应用场景下,红黑树和AVL树有各自的优势和适用性。 红黑树(Red-Black Tr

    2024年02月12日
    浏览(29)
  • 【C++高阶(一)】二叉搜索树深度剖析

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 本章重点: 本篇文章着重讲解二叉搜索树的概念 以及定义,以及二叉搜索树的模拟实现! 最后拓展讲解二叉搜索树的应用场景. 二叉搜索树又

    2024年02月02日
    浏览(27)
  • 【C++高阶(三)】AVL树深度剖析&模拟实现

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++从入门到精通⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 如果你不知道什么是二叉搜索树 请一定先阅读这篇文章: 二叉搜索树深度剖析 为了解决二叉搜索树不稳定的问题 于是乎有人提出了AVL树结

    2024年02月05日
    浏览(31)
  • 【C++进阶06】红黑树图文详解及C++模拟实现红黑树

    1.1 红黑树的概念 AVL树用平衡因子让树达到高度平衡 红黑树可以认为是AVL树的改良 通过给每个节点标记颜色让树接近平衡 以减少树在插入节点的旋转 在每个结点新增一个存储位表示结点颜色 可以是Red或Black 通过对任何一条从根到叶子的路径上 各个结点着色方式的限制 红黑

    2024年01月21日
    浏览(36)
  • 【C++进阶5-红黑树】噩梦般的存在?手提AVLTree暴揍红黑树!

    今天,带来无数人的噩梦——红黑树的讲解。文中不足错漏之处望请斧正! 如果还没看过AVLTree讲解的一定要去看看,看完才能更好理解红黑树! 红黑树是自平衡的二叉搜索树。 红黑树的规则: 每个结点非黑即红 根结点为黑 叶子结点为黑(此处的叶子结点指空结点) 不能有

    2024年02月07日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包