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

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

目录

一.  红黑树的概念及性质

二.  红黑树结点结构的定义

三.  红黑树的插入操作

     1. 情况一

     2. 情况二

       3. 情况三

四.  红黑树的验证

五.  红黑树与AVL树的比较


一.  红黑树的概念及性质

红黑树是一种自平衡的二叉搜索树,它在每个节点上增加了一个存储位来表示节点的颜色,
可以是红色或黑色。

【数据结构】二叉树---红黑树的实现,《数据结构&算法》,数据结构,算法,c++

红黑树具有以下性质

   1. 每个结点要么是红色,要么是黑色
   2. 根结点是黑色
   3. 每个叶结点(NIL结点,空结点)是黑色
   4. 如果一个结点红色,则它的子结点必须黑色(所有路径上不能有两个连续的红色节点)

   5. 从任一结点到其每个叶子的所有路径都包含相同数目黑色


        这些性质保证了红黑树的关键性质,从根到叶子的最长路径不会超过最短路径的两倍,从而保证了红黑树的平衡性。红黑树常被用于实现集合和映射等数据结构,因为其在插入、删除等操作上具有较好的性能表现

二.  红黑树结点结构的定义

红黑树节点结构通常包含以下几个字段:

       键值(key):用于比较和排序节点的值。
       指向父节点的指针(parent):指向当前节点的父节点。
       指向左节点的指针(left):指向当前节点的左节点。
       指向右节点的指针(right):指向当前节点的右节点。
       颜色(color):表示节点的颜色,通常用一个位来表示,比如红色和黑色

红黑树节点结构的定义表示如下:

在这里通过定义枚举结构来表示红、黑两种颜色

//定义结点的颜色
enum Color
{
	RED,    //表示红色
	BLACK   //表示黑色
};

//红黑树的结点定义类模板
template<class T>
struct RBTreeNode
{
	RBTreeNode<T>* _left;    //指向左结点
	RBTreeNode<T>* _right;   //指向右节点
	RBTreeNode<T>* _parent;  //指向父节点(红黑树需要旋转,为了实现简单给出该字段)          
	T _data;        //结点值
	Color _col;     //结点的颜色

    //结点的构造函数
	RBTreeNode(const T& data)
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _col(RED)      //默认初始化红色
	{}

};

注意:这里将插入结点的默认颜色给成红色

  

       当插入一个新节点时,如果将该节点默认设置为黑色,可能会破坏红黑树的性质,需要进行额外的操作来恢复平衡。而将新插入的节点默认设置为红色,是为了满足红黑树的性质,特别是在插入节点时能够更容易地维持这些性质。红黑树的性质要求如果一个节点是红色,则其子节点必须是黑色,这是为了确保从根节点到叶子节点的每条路径上黑色节点的数量相等,从而保持树的平衡性。

       因此,将节点的默认颜色设置为红色是为了简化插入操作,并确保在插入新节点后能够更轻松地维护红黑树的平衡性。

三.  红黑树的插入操作

       因为新节点的默认颜色是红色,因此:如果其双亲节点的颜色是黑色,没有违反红黑树任何性质,则不需要调整但当新插入节点的双亲节点颜色为红色时,就违反了性质4,不能有连续的红色节点,此时需要对红黑树分情况来讨论:

说明:这里所用到的字段
                C 表示当前新插入节点,

                P 表示父节点(当前节点的父节点),
                G 表示祖父节点(父节点的父节点),

                U 表示叔叔节点(父节点的兄弟节点)

     1. 情况一

新插入节点(C)的父节点(P)是红色,且新插入节点的叔叔节点(U)(父节点的兄弟节点) 存在且是红色
这时需要进行颜色调整和递归调整。     

颜色调整:将 P 和 U 改为 黑,G 改为 红

注意:G若为根结点,则改为黑色

           G若为子树,则继续递归向上调整

【数据结构】二叉树---红黑树的实现,《数据结构&amp;算法》,数据结构,算法,c++

     2. 情况二

新插入节点(C)的父节点(P)是红色,但新插入结点的叔叔节点(U)是黑色或空节点:

 叔叔结点(U)不为空

    1. 父节点(P)是其祖父节点(G)的左节点,新插入节点(C)是其父节点(P)的右节点,左单旋转

    2. 父节点(P)是其祖父节点(G)的右节点,新插入节点(C)是其父节点(P)的左节点,右单旋转


 颜色调整 :G 改为 红,C 改为 黑            

【数据结构】二叉树---红黑树的实现,《数据结构&amp;算法》,数据结构,算法,c++

       3. 情况三

新节点(C)的父节点(P)是红色,但新节点的叔叔节点(U)是黑色或空节点

 叔叔结点(U)为空

    1. 父节点(P)是其祖父节点(G)的左节点,新插入节点(C)是其父节点(P)的左节点,单旋转

    2. 父节点(P)是其祖父节点(G)的右节点,新插入节点(C)是其父节点(P)的右节点,单旋转

颜色调整 :P 改为 黑,G 改为 红

【数据结构】二叉树---红黑树的实现,《数据结构&amp;算法》,数据结构,算法,c++

	bool Insert(const T& data)
	{
		if (_root == nullptr)
		{
			_root = new Node(data);
			_root->_col = BLACK;
			return true;
		}
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_data> data)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_data < data)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		cur = new Node(data); 
		if (cur->_data < parent->_data)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		while (parent && parent->_col == RED)
		{
			Node* grandfather = parent->_parent;
			//一:父节点在祖父节点的左侧
			if (parent == grandfather->_left)
			{
				Node* uncle = grandfather->_right;
				//情况1:叔叔节点存在且为红;
				if (uncle && uncle->_col == RED)
				{
					//父和叔叔节点变为黑色,祖父节点变为红色
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上处理
					cur = grandfather;
					parent = grandfather->_parent;
				}
				else
				{
					//情况2:叔叔不存在 或 叔叔存在且为黑色
					//旋转 + 变色
					if (cur == parent->_left) //cur在parent的左
					{
						RotateR(grandfather);   //以grandfather进行右单旋转
						parent->_col = BLACK;   //调整颜色
						grandfather->_col = RED;
					}
					else                      //cur在parent的右
					{
						RotateL(parent);         //以parent进行左旋
						RotateR(grandfather);    //以grandfather进行右旋
						cur->_col = BLACK;       //调整颜色
						grandfather->_col = RED; 
					}
					break;
				}
			}
			else  //二:父节点在祖父节点的右侧
			{
				Node* uncle = grandfather->_left;
				//情况1:叔叔节点存在且为红;
				if (uncle && uncle->_col == RED)
				{
					//父和叔叔节点变为黑色,祖父节点变为红色
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandfather->_col = RED;

					//继续往上处理
					cur = grandfather;
					parent = grandfather->_parent;
				}
				else
				{
					//情况2:叔叔不存在 或 叔叔存在且为黑色
					//旋转 + 调整颜色
					// cur在parent的右
					if (cur == parent->_right)
					{
						RotateL(grandfather);   //以grandfather进行右单旋转
						parent->_col = BLACK;   //调整颜色
						grandfather->_col = RED;
					}
					else  // cur在parent的左
					{
						RotateR(parent);         //以parent进行右旋
						RotateL(grandfather);    //以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;
		subR->_left = parent;

		Node* ppnode = parent->_parent;         
		parent->_parent = subR;                 
		if (parent == _root)                    
		{
			_root = subR;
			subR->_parent = nullptr;
		}
		else
		{
			if (ppnode->_right == parent)
			{
				ppnode->_right = subR;
			}
			else
			{
				ppnode->_left = subR;
			}
			subR->_parent = ppnode;
		}
	}

	// 右单旋
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;

		parent->_left = subLR;
		if (subLR)                  
			subLR->_parent = parent;
		subL->_right = parent;

		Node* ppnode = parent->_parent;     
		parent->_parent = subL;             
		if (parent == _root)                
		{
			_root = subL;
			subL->_parent = nullptr;
		}
		else
		{
			if (ppnode->_left == parent)
			{
				ppnode->_left = subL;
			}
			else
			{
				ppnode->_right = subL;
			}
			subL->_parent = ppnode;
		}
	}

四.  红黑树的验证

红黑树的验证分为两步:

     1. 验证其是否满足二叉搜索树

                中序遍历是否为有序序列

     2. 验证其是否满足红黑树的性质

              1. 根是黑色的
              2. 没有连续的红色节点
              3. 每条路径的黑色节点的数量相等

	//中序遍历 验证是否有序
    void InOrder(Node* root)
	{
		if (root == nullptr)
			return;
		InOrder(root->_left);
		cout << root->_data << " ";
		InOrder(root->_right);

	}

    //验证是否满足红黑树的性质
    bool IsValidRBTRee()
	{
		if (_root && _root->_col == RED)
			return false;

		int refBlackNum = 0;  //作为路径上黑色节点的参考值
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				refBlackNum++;
			cur = cur->_left;
		}
		return _IsValidRBTRee(_root, 0, refBlackNum);
	}

    // 检测红黑树是否为有效的红黑树
	bool _IsValidRBTRee(Node* root, int blackNum, int refBlackNum)
	{
		if (root == nullptr)  //每条路径的黑色节点的数量是否相等
		{
			if (blackNum != refBlackNum)
			{
				cout << "黑色节点的数量不相等" << endl;
				return false;
			}
			cout << blackNum << endl;   
			return true;
		}

        //是否存在连续的红节点
		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << root->_kv.first << "存在连续的红色节点" << endl;
			return false;
		}
        
        // 统计黑色节点的个数
		if (root->_col == BLACK)
		{
			blackNum++;
		}

		return _IsValidRBTRee(root->_left, blackNum, refBlackNum)
			&& _IsValidRBTRee(root->_right, blackNum, refBlackNum);
	}

五.  红黑树与AVL树的比较

红黑树和AVL树是两种常见的自平衡二叉搜索树结构。它们都可以保持树的平衡,以确保在插入和删除操作后,树的高度始终保持在较小的范围内,从而保证了检索、插入和删除操作的时间复杂度为O(logn)

 一,对平衡性要求  

        1. AVL树要求严格的平衡性,即任意节点的左右子树的高度差的绝对值不超过1

        2. 红黑树放宽了对平衡性的要求,它通过引入红黑节点的颜色来保持大致平衡,即任意节点的黑结点高度相等

二,插入和删除操作的性能

        1. AVL树对插入和删除操作的平均性能略低于红黑树,因为AVL树需要更频繁地进行旋转操作来保持严格的平衡。

        2. 红黑树在插入和删除操作时的性能相对较好,因为它对平衡性的要求较松,旋转的次数相对较少

三,查询性能

        由于两种树结构的高度始终保持在较小范围内,它们的查询性能相似,都为O(logn)文章来源地址https://www.toymoban.com/news/detail-842107.html


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

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

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

相关文章

  • 【数据结构大全】你想要的都有,数组、链表、堆栈、二叉树、红黑树、B树、图......

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

    2024年02月10日
    浏览(46)
  • 数据结构与算法(三):树论(树形结构、二叉树、二叉搜索树、红黑树、Btree&B+Tree、赫夫曼树、堆树)

    树论(树形结构、二叉树、二叉搜索树、红黑树、Btree、B+Tree、赫夫曼树、堆树) 在树形结构里面重要的术语: 结点:树里面的元素。 父子关系:结点之间相连的边 子树:当结点大于1时,其余的结点分为的互不相交的集合称为子树 度:一个结点拥有的子树数量称为结点的

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

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

    2024年02月09日
    浏览(49)
  • Java 数据结构篇-实现红黑树的核心方法

      🔥博客主页: 【 小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍      文章目录         1.0 红黑树的说明         2.0 红黑树的特性         3.0 红黑树的成员变量及其构造方法         4.0 实现红黑树的核心方法         4.1 红黑树内部类的核心方法         (1)判

    2024年01月24日
    浏览(45)
  • 【数据结构】红黑树的删除(抽丝剥茧,带你理清每一种情况)

     红黑树的删除,较AVL树的删除比较抽象,同时也跟红黑树的插入的区别较大,但大体上的思路还是基于普通二叉搜索树的基础上进行讨论的。 浅浅的铺垫一下: 需要清楚普通二叉树的删除,可见AVL树的删除文章开头。 四种旋转的操作(只需操作)得熟记于心,可见AVL树的插

    2024年04月27日
    浏览(34)
  • 【数据结构】树、二叉树的概念和二叉树的顺序结构及实现

    之前我们学习了顺序表、链表以及栈和队列这些数据结构,但这些数据结构都是线性的(一对一)。接下来要学习 非线性的数据结构——树(二叉树) ,相比前面的,树的结构更加复杂,话不多说,直接进入正题吧。 树是一种 非线性的数据结构 ,它是 一对多(也有可能是

    2024年02月07日
    浏览(42)
  • 数据结构——二叉树的链式结构

      个人主页 : 日刷百题 系列专栏 : 〖C语言小游戏〗〖Linux〗〖数据结构〗  〖C语言〗 🌎 欢迎各位 → 点赞 👍+ 收藏 ⭐️+ 留言 📝  ​ 这里我们使用先序遍历的思想来创建二叉树,这里的内容对于刚接触二叉树的朋友可能有些难理解,不妨先看完下面的二叉树各种遍历

    2024年02月05日
    浏览(48)
  • 【数据结构】二叉树的链式结构

    学习链式二叉树要知道三种遍历方式,便于对二叉树的节点以及左子树和右子树进行操作。 前序遍历:根、左子树、右子树 中序遍历:左子树、根、右子树 后序遍历:左子树、右子树、根 以下图为例: 得到的结果: 前序遍历:1 2 3 4 5 6 中序遍历:3 2 1 5 4 6 后序遍历:3 2

    2024年02月08日
    浏览(57)
  • 数据结构:二叉树的链式结构

    朋友们、伙计们,我们又见面了,本期来给大家解读一下链式二叉树的相关知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! 数据结构与算法专栏 :数据结构与算法 个  人  主  页 :stackY、 C 语 言 专 栏 :C语言:从入门到精通 目录 前言

    2024年02月07日
    浏览(59)
  • 【数据结构】二叉树的介绍和二叉树堆

    💓作者简介: 加油,旭杏,目前大二,正在学习 C++ , 数据结构 等👀 💓作者主页:加油,旭杏的主页👀 ⏩本文收录在:再识C进阶的专栏👀 🚚代码仓库:旭日东升 1👀 🌹欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖        树这一概念,在我们刚开始听说的时候会觉得

    2024年01月20日
    浏览(52)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包