IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++红黑树】带图详细解答红黑树的插入,测试自己的红黑树是否正确的代码 -> 正文阅读

[C++知识库]【C++红黑树】带图详细解答红黑树的插入,测试自己的红黑树是否正确的代码

目录

1.红黑树的概念

1.1红黑树的特性(4+1)

2.红黑树的框架?

3.红黑树的插入?

????????3.1parent在grandfather的左边

?????????3.1parent在grandfather的右边

?4.测试自己的红黑树是不是平衡的


1.红黑树的概念

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

  • 所以它是一个弱平衡二叉搜索树,AVL1树是一个严格的平衡二叉搜索树

1.1红黑树的特性(4+1)

  1. 每个结点不是红色就是黑色
  2. 根节点是黑色的
  3. 如果一个节点是红色的,则它的所有的孩子结点是黑色的
  4. 对于每个结点,从该结点到其所有后代叶结点的路径上,均包含相同数目的黑色结点

每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

  • 我认为这一条只是标记的作用,让我们更好分别每一条路径

?

2.红黑树的框架?

//枚举颜色
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>
class RBtree
{
	typedef RBtreeNode<K,V> Node;
public:
	RBtree()
		:_root(nullptr)
	{}
	
    //旋转
	void RotateL(Node* parent)
	void RotateR(Node* parent)
    //插入
	pair<Node*, bool> Insert(const pair<K, V> kv)
    //寻找
	Node* Find(const K& key)
    //测试自己的写的的红黑树,是否合适
	bool CheckBalance()

private:
	Node* _root;

};

3.红黑树的插入?

pair<Node*, bool> Insert(const pair<K, V> kv)
    //是否为空树
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return make_pair(_root, true);
		}
		Node* cur = _root,*parent=_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 make_pair(cur, false);
			}
		}
		Node* newnode = new Node(kv);
		newnode->_col = RED;
		if (parent->_kv.first < kv.first)
		{
			parent->_right = newnode;
			newnode->_parent = parent;
		}
		else
		{
			parent->_left = newnode;
			newnode->_parent = parent;
		}
		cur = newnode;
		while (parent && parent->_col == RED)
		{
			// 如果父亲存在,且颜色为红色就需要处理
			Node* grandfather = parent->_parent;
			if (parent == grandfather->_left)
			{
				// 关键是看叔叔
				Node* uncle = grandfather->_right;
				// 情况1:uncle存在且为红
				if (uncle&&uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					// 继续往上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else// 情况2+3:uncle不存在 uncle存在且为黑
				{
					// 情况2:单旋
					if (cur == parent->_left)
					{
						RotateR(grandfather);

						parent->_col = BLACK ;
						grandfather->_col = RED;
					}
					// 情况3:双旋
					else
					{
						RotateL(parent);
						RotateR(grandfather);

						cur->_col = BLACK;
						grandfather->_col = RED;
					}
					//最上面的节点已经变黑了,不用继续
					break;
				}
			}
			// 如果父亲存在,且颜色为红色就需要处理
			else
			{
				// 关键是看叔叔
				Node* uncle = grandfather->_left;
				// 情况1:uncle存在且为红
				if (uncle && uncle->_col == RED)
				{
					parent->_col = uncle->_col = BLACK;
					grandfather->_col = RED;
					// 继续往上处理
					cur = grandfather;
					parent = cur->_parent;
				}
				else // 情况2 + 3:uncle不存在 uncle存在且为黑
				{
					// 情况2:单旋
					if (cur == parent->_right)
					{
						RotateL(grandfather);

						parent->_col = BLACK;
						grandfather->_col = RED;
					}
					// 情况3:双旋
					else
					{
						RotateR(parent);
						RotateL(grandfather);

						cur->_col = BLACK;
						grandfather->_col = RED;
					}
				}
				break;
			}
		}
		_root->_col = BLACK;
		return make_pair(newnode, true);
	}

?插入整体逻辑:

  1. 如果还没有元素是一课空树,直接插入即可;如果有元素,按pair的first(key)和比较的节点比较结果为大说明为空的那个位置在右边,和比较的节点比较的结果小说明为空的哪个位置在左边;如果相等说明已经有这个元素了,二叉搜索树不支持冗余,插入失败则,返回一个pair类第一个成员为那个相同元素的map的迭代器和第二个成员为false的pair类迭代器;
  2. 不知道这个已经找到的位置在父节点的左边还是右边,需要判断一下,然后插入元素;
  3. 考虑变色

3.1不平衡处理

如果有父亲且父亲为红色说明不平衡,就一直向上调整,直到cur到头节点或者parent为黑色

1.第一种情况:有uncle并且uncle为红色处理:parent和uncle变为黑色,grandfather变红色

  • 一直向上调整可能会让头节点变红,那么就在循环外把头节点处理一下

?2.第二种情况,没有uncle或者有uncle且为黑色,有uncle一定是第一种情况变化而来

3.1parent在grandfather的左边

这种情况单纯的变色已经做不到平衡了,怎么办?

旋转处理:parent在grandfather的左边,右单旋和左右双旋

?3.1parent在grandfather的右边

  • 逻辑和在左边是一样的,大家可以自己尝试画一下
  • 旋转我在AVL树右详细解答http://t.csdn.cn/AlRzI

旋转代码:

void RotateL(Node* parent)
	{
		Node* subR = parent->_right;
		Node* subRL = subR->_left;

		parent->_right = subRL;
		if (subRL)
		{
			subRL->_parent = parent;
		}

		subR->_left = parent;
		Node* parentParent = parent->_parent;
		parent->_parent = subR;

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

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

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

		subL->_right = parent;
		Node* parentParent = parent->_parent;
		parent->_parent = subL;

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

			subL->_parent = parentParent;
		}
	}

?4.测试自己的红黑树是不是平衡的

  • 测试了头节点是不是黑色,是否有连续的红节点,每条路径上的黑节点
bool _CheckBalance(Node* root,int LeftNum,int count)
	{
		if (root == nullptr)
		{
			if (count != LeftNum)
			{
				return false;
			}
			return true;
		}
		if (root->_col == RED && root->_parent->_col == RED)
		{
			cout << "存在连续的红色节点" << endl;
			return false;
		}
		if (root->_col == BLACK)
		{
			count++;
		}
		return _CheckBalance(root->_left, LeftNum, count) && 
			_CheckBalance(root->_right, LeftNum, count);
	}
	bool CheckBalance()
	{
		if (_root == nullptr)
		{
			//空树是红黑树
			return true;
		}
		else if(_root->_col==RED)
		{
			cout << "根节点是红色的" << endl;
			return false;
		}
		else
		{
			int LeftNum = 0;
			Node* left = _root;
			// 找最左路径做黑色节点数量参考值
			while (left)
			{
				if (left->_col == BLACK)
				{
					LeftNum++;
				}
				left = left->_left;
			}
			int count = 0;
			return _CheckBalance(_root, LeftNum, count);
		}
	}

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:06:35  更:2022-11-05 00:08:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 2:49:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码