用C++实现红黑树的插入操作以及红黑树的验证

1.红黑树的概念

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

2.红黑树的性质(重要)

  • 每个结点的颜色不是红色就是黑色
  • 根结点的颜色是黑的
  • 如果一个结点是红的,则它的两个孩子结点是黑的(意思是不可能存在连续的红结点)
  • 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点
  • 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

满足以上性质,红黑树就能保证:其最长路径的结点个数不会超过最短路径结点个数的两倍。

为什么呢?因为最短路径是全黑,最长路径是红黑相间,即:

3.红黑树的插入操作

插入新结点的默认颜色给成红色,因为插入之前所有根至外部结点的路径上黑色结点数目都相同,所以如果插入的结点是黑色肯定错误(黑色结点数目就不同了),而插入红结点可能会也可能不会违反“没有连续两个结点是红色”的条件,所以插入的结点为红色。如果违反了条件就再调整。

思路:

1)按照二叉搜索树的规则插入新结点

2)检测新结点插入后,红黑树的性质是否遭到破坏

因为新结点的默认颜色是红色,因此:如果其双亲结点的颜色是黑色,没有违反红黑树的性质,不需要调整;但当新插入结点的双亲结点是红色时,就违反了性质三不能有连在一起的红色结点,此时需要对红黑树分情况讨论:parent在祖父的左侧和parent在祖父的右侧。

 

相关代码如下:

#pragma once
#include<iostream>

using std::cout;
using std::endl;

enum Color
{
	RED,
	BLACK
};
template<class T>
struct RBTreeNode
{
	RBTreeNode(const T& data = T(), Color color = RED)
		: _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _data(data)
		, _color(color)
	{}
	RBTreeNode<T>* _left;
	RBTreeNode<T>* _right;
	RBTreeNode<T>* _parent;
	T _data;
	Color _color;
};
template<class T>
class RBTree
{
	typedef RBTreeNode<T> Node;
public:
	RBTree()
		:_root(nullptr)
	{}
	~RBTree()
	{
		Destroy(_root);
	}
	bool Insert(const T& data)
	{
		//第一步:按照二叉搜索树的方式插入新结点
		if (nullptr == _root)
		{
			_root = new Node(data);
			_root->_color = BLACK;
			return true;
		}
		else
		{
			//按照二叉搜索树的特性,在红黑树中找到要插入的位置
			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				if (data < cur->_data)
				{
					parent = cur;
					cur = cur->_left;
				}	
				else if (data > cur->_data)
				{
					parent = cur;
					cur = cur->_right;
				}
				else
					return false;
			}
			//插入新结点
			cur = new Node(data);
			cur->_color = RED;
			if (data < parent->_data)
			{
				parent->_left = cur;
				cur->_parent = parent;
			}	
			else
			{
				parent->_right = cur;
				cur->_parent = parent;
			}
			
			//第二步:检测新结点插入后,红黑树的性质是否遭到破坏,若满足性质直接退出,否则对红黑树进行旋转着色处理
			while (parent && RED == parent->_color)
			{
				//此时grandfather一定存在,因为parent存在,且颜色不是黑色,则parent一定不是根
				Node* grandfather = parent->_parent;
				//parent在左侧的情况
				if (parent == grandfather->_left)
				{
					Node* uncle = grandfather->_right;
					if (uncle && RED == uncle->_color)
					{
						//叔叔结点存在且为红色
						parent->_color = uncle->_color = BLACK;
						grandfather->_color = RED;
						cur = grandfather;
						parent = cur->_parent;
					}
					else
					{
						//叔叔结点不存在,或叔叔结点存在且为黑色
						if (cur == parent->_right)
						{
							RotateL(parent);
						}
						grandfather->_color = RED;
						parent->_color = BLACK;
						RotateR(grandfather);
						break;
					}
				}
				//parent在右侧的情况
				else
				{
					Node* uncle = grandfather->_left;
					if (uncle && RED == uncle->_color)
					{
						parent->_color = uncle->_color = BLACK;
						grandfather->_color = RED;
						cur = grandfather;
						parent = cur->_parent;
					}
					else
					{
						if (cur == parent->_left)
						{
							RotateR(parent);
						}
						RotateL(grandfather);
						grandfather->_color = RED;
						parent->_color = BLACK;
						break;
					}
				}
			}
			_root->_color = 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* pparent = parent->_parent;
		parent->_parent = subR;
		if (parent == _root)
		{
			_root = subR;
		}
		else
		{
			if (pparent->_left == parent)
			{
				pparent->_left = subR;
			}
			else
			{
				pparent->_right = subR;
			}
		}
		subR->_parent = pparent;
	}
	void RotateR(Node* parent)
	{
		Node* subL = parent->_left;
		Node* subLR = subL->_right;
		parent->_left = subLR;
		if (subLR)
		{
			subLR->_parent = parent;
		}
		Node* pparent = parent->_parent;
		subL->_right = parent;
		parent->_parent = subL;
		if (parent == _root)
		{
			_root = subL;
		}
		else
		{
			if (pparent->_left == parent)
			{
				pparent->_left = subL;
			}
			else
			{
				pparent->_right = subL;
			}
		}
		subL->_parent = pparent;
	}
	void Inorder()
	{
		_Inorder(_root);
		cout << endl;
	}
bool IsRBtree()
	{
		//空树也是红黑树
		if (nullptr == _root)
			return true;
		//检测根节点是否满足红黑树的性质
		if (BLACK != _root->_color)
		{
			cout << "违反红黑树性质:根节点必须为黑色" << endl;
			return false;
		}
		//获取任意一条路径中黑色结点的个数
		size_t blackCount = 0;
		Node* cur = _root;
		while (cur)
		{
			if (BLACK == cur->_color)
				blackCount++;
			cur = cur->_left;
		}
		size_t k = 0;//k用来记录路径中黑色结点的个数
		return _IsRBTree(_root, k, blackCount);
	}
private:
	void _Inorder(Node* root)
	{
		if (root)
		{
			_Inorder(root->_left);
			cout << root->_data << " ";
			_Inorder(root->_right);
		}
	}
	void Destroy(Node* root)
	{
		if (root)
		{
			Destroy(root->_left);
			Destroy(root->_right);
			root = nullptr;
		}
	}
bool _IsRBTree(Node* root, size_t k, const size_t blackCount)
	{
		if (nullptr == root)
			return true;
		//统计黑色结点的个数
		if (BLACK == root->_color)
			k++;
		//检测当前结点与其双亲结点是否都为红色
		Node* parent = root->_parent;
		if (parent && RED == parent->_color && RED == root->_color)
		{
			cout << "违反红黑树性质:没有连在一起的红色结点" << endl;
			return false;
		}
		//检测当前路径中黑色结点的个数是否与其他路径中的黑色结点相等
		if (nullptr == root->_left && nullptr == root->_right)
		{
			if (k != blackCount)
			{
				cout << "违反红黑树性质:每条路径中黑色结点的个数必须相等" << endl;
				return false;
			}
		}
	return _IsRBTree(root->_left, k, blackCount) && _IsRBTree(root->_right,k,blackCount);
	}
private:
	Node* _root;
};
void TestRBTree()
{
	RBTree<int> rt1;
	rt1.Insert(2);
	rt1.Insert(8);
	rt1.Insert(11);
	rt1.Insert(13);
	rt1.Insert(17);
	rt1.Inorder();
        rt1.IsRBTree();
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值