一文带你搞懂红黑树的基本操作

#编程小白如何成为大神?大学新生的最佳入门攻略#

1.红黑树的性质

1.每个节点只有红色和黑色两种形态

2.根节点是黑色的

3.如果一个节点是红色的,那么它的两个孩子是黑色的,也就是一条路径不存在连续的红色节点

4.对于每个节点,从该节点到其后代的简单路径上均包含数目相同的黑色节点

5.每个空节点都是黑色的

6.最长路径的节点不超过最短的两倍(最短为纯黑节点)

2.红黑树的插入

插入一般选择红色节点,因为黑色就会破坏股则4,但是红色不一定破坏规则3,因为可以插到黑色节点的下面

将插入时的红黑树推断为以上形式,g祖父节点,p父亲节点,u叔叔节点,cur自己

情况1:g黑,pu红,cur红

解决方法:g改成红,pu改成黑,把g当成cur继续向上调整(g如果是根节点就改回来)

情况2:g黑p红u黑或不存在cur红,g,p,cur为左侧的一个路径

解决方法:先对g进行右单旋,p变黑,g变红

情况3:与情况2相同,只不过cur是p的右孩子

解决方法:左单旋

情况4:cur,p为红g,u为黑(u可以不存在),g,pcur是右侧路径

解决方法:对g进行左单旋,p变黑g变红

 情况5:同情况4,只不过cur是p的左孩子

解决方法:先右单旋变成情况4,再解决情况4

#include<iostream>
using namespace std;
enum Color
{
	RED,
	BLACK
};
template<class K, class V>
struct RBTreeNode
{
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;
	RBTreeNode<K, V>* _parent;
	pair<K, V> _kv;
	Color _col;
	RBTreeNode(pair<K, V>& kv = pair<K, V>())
		:_left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _kv(kv)
		, _col(RED)
};
template<class K, class V>
class RBTree
{
protected:
	typedef RBTreeNode<K, V> Node;
public:
	bool Insert(pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(val);
			_root->_col = BLACK;//根肯定是黑色的
			return true;
		}
		else
		{
			Node* cur = _root;
			Node* parent = nullptr
				while (cur)
				{
					parent = cur;
					if (cur->_val > val)
						cur = cur->left;
					else if (cur->_val < val)
						cur = cur->_right;
					else
						return false;
				}
			cur = new Node(val);
			if (parent->_val.first > cur->_val.first)
			{
				parent->_left = cur;
			}
			else
			{
				parent->_parent = cur;
			}
			cur->_parent = parent;
			///从此处开始进行插入后的调整
			while (parent && parent->_col == RED)//出问题了
			{
				Node* grandparent = parent->_parent;
				Node* uncle = nullptr;
				if (grandparent->_left == parent)//找叔叔分情况
					uncle = grandparent->_right;
				else
					uncle = grandparent->_left;
				if (uncle && uncle->_col == RED)//叔叔是红色的,变色
				{
					parent->_col = BLACK;
					uncle->_col = BLACK;
					grandparent->_col = RED;
					cur = grandparent;
					parent = cur->_parent;
				}
				else if (grandparent->_left == parent)//叔叔是黑色或者不存在,且p是左侧路径,第二
				{
					if (parent->_left = cur)
					{
						RotateR(grandparent);
						grandparent->_col = RED;
						parent->_col = BLACK;
					}
					else//此时p是右侧路径是情况3
					{
						RotateL(parent);
						RotateR(grandparent);
						grandparent->_col = RED;
						cur->_col = BLACK;
					}
				}
				else//叔叔是黑色或者不存在,且p是右侧路径
				{
					if (parent->_right = cur)//情况4
					{
						RotateL(grandparent);
						grandparent->_col = RED;
						parent->_col = BLACK;
					}
					else//情况5
					{
						RotateR(parent);
						RotateL(grandparent);
						grandparent->_col = RED;
						cur->_col = BLACK;
					}
				}
				void RotateL(RBTNode * parent)//左旋
				{
					Node* grandparent = parent->_parent;
					Node* ChildR = parent->_right;
					if (grandparent)
					{
						if (grandparent->_left == parent)
							grandparent->_left = ChildR;
						else
							grandparent->_right = ChildR;
					}
					else
						_root = ChildR;
					ChildR->_parent = grandparent;
					parent->_right = ChildR->_left;
					ChildR->_left->_parent = parent;
					ChildR->_left = parent;
					parent->_parent = ChildR;
				
				}
				void RotateR(RBTNode * parent)//右旋
				{
					Node* grandparent = parent->_parent;
					Node* ChildL = parent->_left;
					if (grandparent)
					{
						if (grandparent->_left == parent)
							grandparent->_left = ChildL;
						else
							grandparent->_right = ChildL;
					}
					else
						_root = ChildL;
					ChildL->_parent = grandparent;
					//两两一组进行改变
					parent->_left = ChildL->_right;
					ChildL->_right->_parent = parent;

					ChildL->_right = parent;
					parent->_parent = ChildL;//
				
				}
		
				
			}

		}
	}
protected:
	Node* _root;
};

3.验证红黑树

void Inorde(RBTNode * root, vector<pair<K, V>>&v)
{
				if (root == nullptr)
					return;
				Inorde(root->_left, v);
				v.push_back(root->_val);
				Inorde(root->_right, v);
}

检查是否是二叉搜索树

检验性质

bool IsBalance(Node*root)
{
	//空树也是红黑树
	if (root == nullptr)
		return true;
	//违反性质2
	if (root->_col == RED)
 
	{
		cout << "树的根节点应该是黑色,可该树却是红色" << endl;
		return false;
	}
	//计算一条路径黑节点数量
	Node* cur = root;
	int num = 0;
	while (cur)
	{
		if (cur->_col == BLACK)
			num++;
		cur = cur->_left;
	}
	return _IsBlance(root,0,num);
}
_IsBalance(Node* root, size_t num, size_t cur_num)
{
	if (root == nullptr)
	{
		//违反性质4
		if (num != cur_num)
		{
			cout << "对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点,但该树却不是" << endl
				return false;
		}
		else
		return true;
	}
	if (root->_col == BLACK)
		num++;
	//违反性质3
	if (root->_parent && root->_parent == RED && root->_col == RED)
	{
		cout << "如果一个节点是红色的,则它的两个孩子结点是黑色的,可该树却出现了连续的红色节点" << endl;
		return false;
	}
	return IsBalance(root->_left, num, cur_num) && IsBalance(root->_right, num, cur_num);
}

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值