搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现

这篇具有很好参考价值的文章主要介绍了搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


黑红树是一颗特殊的搜索二叉树,本文在前文的基础上,图解红黑树插入:前文 链接,完整对部分关键代码展示,完整的代码在gitee仓库中: 链接
文章中有错误的地方,欢迎大家指正!如果有帮助到你,也请多多点赞支持!
1.红黑树的概述

平衡二叉树要求左右子树的高度差的绝对值不超过1,所以平衡二叉树是高度平衡的,正是因为它要求严格控制高度差,在频繁的插入的删除的时候导致旋转次数过多带来了一定的性能消耗!

红黑树也是一颗特殊的搜索二叉树,任何一条从根到叶子的路径上各个结点由颜色(红黑)方式的限制,红黑树确保没有一条路径会比其他路径长出两倍(最长路径不会超过最短路径的两倍),它而是接近平衡的。红黑树没有严格要求高度的平衡,所以红黑树在总体的性能上会略优于平衡二叉树(AVL树)。

在现实的各种应用中都是使用红黑树的来充当数据结构,如:Java集合中的TreeMap,C++STL中Set、Map等都是使用红黑树而不是AVL树。可能在查找方面AVL树会由于红黑树,但是几十次的常数差别,在现代CPU(大概每秒几十亿次)来说完全不受影响,AVL树和红黑树查找的时间复杂度都是在一个等级上O(log_2(N)),红黑树在插入和删除会优于AVL树!

2.红黑树的性质
  1. 每个结点不是红色就是黑色
  2. 根节点必须是黑色的
  3. 如果一个节点是红色的,则它的两个孩子结点必须是是黑色的,(即:不会有两个连续的红节点)
  4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点(即:每条路径上黑色的节点相同)
  5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点,即下图的NIL)

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

关于路径问题

上图有11条路径

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

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

最短路径:全黑的路径 最长路径:一黑一红相间的路径

上面的图情况就是最大的(4个节点/2个节点 = 2倍)的情况!

3.红黑树的代码实现
3.1.红黑树的节点定义
enum color
{
    RED,
    BLACK
};

template<class K, class V>
struct RBNode
{
    std::pair<K, V> _kv;

    RBNode<K, V>* _left;
    RBNode<K, V>* _right;
    RBNode<K, V>* _parent;
    color _color;

    RBNode(const std::pair<K, V> kv)
        :_kv(kv)
        , _left(nullptr)
        , _right(nullptr)
        , _parent(nullptr)
        , _color(RED)
    {}
};
3.2.红黑树的插入操作

第一大类情况:cur、parent为红,grandfather为黑,uncle存在且为红!

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

  1. 将parent和uncle都变为黑,grandfather变为红
  2. 但是grandfather,如果是根节点直接将其设为黑即可,
  3. 如果grandfather不为红,如下图:则将cur = grandfather继续重复步骤1和步骤2

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

**第二大类情况:**cur为红,parent为红,grandfather为黑,uncle不存在或uncle存在且为黑

单旋的情况:

  1. 下图是uncle不存在或uncle存在且为黑单旋的情况,通过节点的位置判断单旋:如条件是grandfather ->left = parent; parent->left = cur; 直线说明是单旋,都是左边说明右边高,要右单旋!
  2. 变色,grandfather变为红,parent变为黑色;可以看到,调整后的根据原来的grandfather是黑色,无论往上的祖先是何种颜色,都不会出现两个红色连一起的情况,不用往上调整了!

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

双旋的情况:

  1. 通过上面的例子可以知道,存在uncle且为黑和不存在uncle的处理结果是一样的!
  2. 通过下图的判断,是折线:grandfather ->left = parnt;parent->right =cur;通过平衡二叉树的插入操作的学习,可以知道,这种情况先左单旋,再右单旋!
  3. 变色:grandfather变为红,cur变为黑;可以看到,调整后的根据原来的grandfather是黑色,无论往上的祖先是何种颜色,都不会出现两个红色连一起的情况,不用往上调整了!

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

上面就是红黑树的**左子树的插入操作!右子树的插入99%是一样的!**可能没有99%,哈哈哈!但是是类似的操作!简单画个图:

第一大类情况

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

第二大类情况

单旋情况:

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

双旋情况:

搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现,常见数据结构,数据结构

bool insert(const std::pair<K, V>& kv)
{
	if (_root == nullptr)
	{
		_root = new Node(kv);
		_root->_color = BLACK;
		return true;
	}

	Node* parent = nullptr;
	Node* cur = _root;
	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;
	}

	cur->_parent = parent;

	while (parent && parent->_color == RED)
	{
		Node* grandfather = parent->_parent;

		// parent是左子树
		if (parent == grandfather->_left)
		{
			
			Node* uncle = grandfather->_right;
			// 第一大类:uncle存在且为红
			if (uncle && uncle->_color == RED)
			{
				// 改变颜色
				parent->_color = uncle->_color = BLACK;
				grandfather->_color = RED;

				// 修改条件,继续往上执行
				cur = grandfather;
				parent = cur->_parent;
			}
			else // 第二大类:uncle不存在或uncle存在且为黑
			{
				// 单旋情况
				if (cur == parent->_left)
				{
					// 右单旋
					RotateRight(grandfather);

					// 改变颜色
					parent->_color = BLACK;
					grandfather->_color = RED;
				}
				else  // 双旋情况
				{
					RotateLeft(parent);
					RotateRight(grandfather);

					cur->_color = BLACK;
					grandfather->_color = RED;
				}

				// 这种情况就不用重复调整,直接跳出循环
				break;
			}
		}
		else // parent是右子树
		{
			Node* uncle = grandfather->_left;

			if (uncle && uncle->_color == RED)
			{
				parent->_color = uncle->_color= BLACK;
				grandfather->_color = RED;

				cur = grandfather;
				parent = cur->_parent;
			}
			else
			{
				if (cur == parent->_right)
				{
					RotateLeft(grandfather);

					parent->_color = BLACK;
					grandfather->_color = RED;
				}
				else
				{
					RotateRight(parent);
					RotateLeft(grandfather);

					cur->_color = BLACK;
					grandfather->_color = RED;
				}
				break;
				
			}
			
		}
	}
	// 根绝对为黑色
	_root->_color = BLACK;

	return true;
}
3.3.红黑树是否平衡

根据每条路径的黑节点的个数相同判断!文章来源地址https://www.toymoban.com/news/detail-833945.html

bool isBanlan()
{
    // 如何判断是否为红黑树
    // 1.高度行不行? 不行! 2.能不能根据节点的个数不操作2倍的关系? 也不行
    // 3.那有什么是确定的?所有路径黑节点的个数相等!根据这个性质!
    Node* cur = _root;

    int checkNum = 0;
    while (cur)
    {
        if(cur->_color == BLACK)
            checkNum++;

        cur = cur->_left;
    }
  
    return isBanlan(_root,checkNum,0); 
}

bool isBanlan(Node* root,int &checkNum,int blackNum)
{
	if (root == nullptr)
		return true;

	if (root->_color == BLACK)
	{
		blackNum++;
	}

	if (root->_left == nullptr && root->_right == nullptr)
	{
		return blackNum == checkNum ? true : false;
	}
	bool left = isBanlan(root->_left, checkNum, blackNum);
	bool right = isBanlan(root->_right, checkNum, blackNum);
	
	return left && right;
}

到了这里,关于搜索二叉树 | 红黑树 | 验证是否为红黑树 | 代码实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【数据结构】二叉树---红黑树的实现

    目录 一.  红黑树的概念及性质 二.  红黑树结点结构的定义 三.  红黑树的插入操作      1. 情况一      2. 情况二        3. 情况三 四.  红黑树的验证 五.  红黑树与AVL树的比较 红黑树是一种自平衡的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,

    2024年03月21日
    浏览(37)
  • 二叉树、二叉查找树、平衡树和红黑树概念及其性质

      在所有的树结构,基本上都遵循左小右大的原则。本文分享二叉树、二叉查找树、平衡树和红黑树概念及其性质。   二叉树(Binary Tree)是指每个节点最多只有两个分支的树结构(即不存在分支大于 2 的节点),如下图所示:   这是一棵拥有 6 个节点深度为 2(深度

    2024年02月08日
    浏览(29)
  • 数据结构-各种树(二叉树、二叉查找树、平衡二叉树、红黑树、B树、B+树)

    概念:二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树 特点:每个

    2024年02月09日
    浏览(38)
  • Java常见的数据结构:栈、队列、数组、链表、二叉树、二叉查找树、平衡二叉树、红黑树

    数据结构是计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。 通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率 栈 队列 数组 链表 二叉树 二叉查找树 平衡二叉树 红黑树... 后进先出,先进后出 数据进入栈模型的过程称为

    2024年02月07日
    浏览(30)
  • 二叉搜索树:红黑树的原理和实现

    💭上文我们在遇到问题:二叉搜索树退化到单支导致效率和性能降低时,利用了AVL树解决。但是由于AVL树是一棵绝对平衡的树,每次修改树结构都要保证左右子树高度差的绝对值不超过1,这可能会引发多次旋转。因此,若我们要设计出一棵结构动态变化的二叉搜索树,利用

    2024年02月01日
    浏览(29)
  • 树、二叉树、哈夫曼树、B树、B+树、红黑树相关计算

    树 树中的节点数等于所有节点的度数之和+1(一个节点的孩子个数称为该节点的度) 度为m的树中第i层上至多有 m i − 1 m^{i-1} m i − 1 个节点 高度为h的m叉树至多有 m h − 1 m − 1 frac{m^h-1}{m-1} m − 1 m h − 1 ​ 个节点 具有n个节点的m叉树的最小高度是 ⌈ l o g m ( n ( m − 1 ) + 1

    2024年02月13日
    浏览(28)
  • MySQL索引为什么选择B+树,而不是二叉树、红黑树、B树?

    二叉树是一种二分查找树,有很好的查找性能,相当于二分查找。 二叉树的非叶子节值大于左边子节点、小于右边子节点。 原因: 但是当N比较大的时候,树的深度比较高。数据查询的时间主要依赖于磁盘IO的次数,二叉树深度越大,查找的次数越多,性能越差。 最坏的情况

    2024年04月25日
    浏览(28)
  • 【数据结构大全】你想要的都有,数组、链表、堆栈、二叉树、红黑树、B树、图......

    作者简介: 目录 1.概述 2.线性结构 3.时间复杂度 4.查找算法 5.树 6.图 博主之前写过一个完整的关于数据结构的系列文章,一共十三篇,内容包含,数组、链表、堆栈、队列、时间复杂度、顺序查找、二分查找、二叉树、二叉搜索树、平衡二叉树、红黑树、B树、B+树、大顶堆

    2024年02月10日
    浏览(35)
  • day20 最大的二叉树 合并二叉树 二叉搜索树中的搜索 验证二叉搜索树

    题目链接:654 最大二叉树 题意 根据不重复的整数数组nums构建最大的二叉树 ,根节点是数组中的最大值,最大值左边的子数组构建左子树,最大值右边的子数组构建右子树 nums数组中最少含有1个元素,并且nums中的元素数值均大于等于0 递归  递归三部曲: 1)确定递归函数的

    2024年01月21日
    浏览(33)
  • 算法刷题Day 20 最大二叉树+合并二叉树+二叉搜索树中的搜索+验证二叉搜索树

    递归 递归 迭代 递归 迭代 遇到两个坑的地方: 递归的时候,不能光验证左子树的根节点小于当前根节点,右子树的根节点大于但当前根节点,别忘了左子树上的每一个节点都要求比根节点要小,右子树上的每一个节点都要求比根节点大。 根节点跟左(右)子树中的某一个节

    2024年02月16日
    浏览(32)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包