C++实现红黑树

一、红黑树的性质

红黑树也是二叉搜索树,它的每个节点增加了一个单位用来表示颜色,可以是Red也可以是Black,通过对任意一条根到叶子节点的颜色来约束,红黑树保证最长路径是最短路径的两倍,因此近似平衡。
红黑树的性质:
1、每个节点不是红色就是黑色
2、树的根节点是黑色
3、如果一个节点是红色,则它的两个孩子节点是黑色的(没有连续的红色)
4、 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点(每条路径上黑色结点的数量相等)
看一下红黑树的节点结构:
enum COLOR
{
	BLACK,
	RED
};

template<class K, class V>
struct RBTreeNode
{
	RBTreeNode(const K& key, const V& value, COLOR color = RED)
	:_pLeft(NULL)
	, _pRight(NULL)
	, _pParent(NULL)
	, _key(key)
	, _value(value)
	, _color(color)
	{}

	RBTreeNode<K, V> *_pLeft;
	RBTreeNode<K, V> *_pRight;
	RBTreeNode<K, V> *_pParent;

	K _key;
	V _value;
	COLOR _color;
};

二、插入节点后分析
1、插入的位置若为根节点,根据性质可知调整为黑色。
2、插入节点后,违反了性质,需要做调整,可能遇到下面三种情况:
注:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

情况一:
cur为红,p为红,g为黑,u存在且为红,如下图:

不能将p直接改为黑色,这样会改变某路径黑色节点的个数。
情况二:

cur为红,p为红,g为黑,u不存在/u为黑,如下图,对树g右旋:

 上图,p为g的左孩子,cur为p的左孩子,则进行右单旋转;同理,p为g的右孩子,cur 为p的右孩子,则进行左单旋转。
注:左旋及右旋的具体过程和AVL树很像,只有少了平衡因子的更新,但是多了变色处理。具体可以参考上篇AVL树。
情况三:

cur为红,p为红,g为黑,u不存在/u为黑,如下图,对树cur左旋:
转化为情况二,对g进行右旋。

上图,p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;同理,p为g的右孩子, cur为p的左孩子,则针对p做右单旋转。
插入算法代码如下:
	bool Insert(const K& key, const V& value)
	{
		if (NULL == _pRoot)
		{
			_pRoot = new Node(key, value, BLACK);   //根节点为黑色
			return true;
		}

		//找插入位置
		pNode pCur = _pRoot;
		pNode pParent = NULL;

		while (pCur)
		{
			if (key < pCur->_key)
			{
				pParent = pCur;
				pCur = pCur->_pLeft;
			}
			else if (key > pCur->_key)
			{
				pParent = pCur;
				pCur = pCur->_pRight;
			}
			else
			{
				return false;
			}
		}

		pCur = new Node(key, value);
		if (key < pParent->_key)
			pParent->_pLeft = pCur;
		else
			pParent->_pRight = pCur;

		pCur->_pParent = pParent;

		//有可能会违反红黑树的性质---3
		while (pParent&&pParent->_color == RED)
		{
			pNode grandParent = pParent->_pParent;
			if (pParent == grandParent->_pLeft)
			{
				pNode uncle = grandParent->_pRight;
				//情况一,叔叔节点存在且为红
				if (uncle&&uncle->_color == RED)
				{
					pParent->_color = BLACK;
					uncle->_color = BLACK;
					grandParent->_color = RED;

					pCur = grandParent;   //继续向上调整
					pParent = pCur->_pParent;
				}

				//叔叔不存在或者存在且为黑
				else
				{
					//若是第三种情况转化为第二种
					if (pCur == pParent->_pRight)
					{
						RotateL(pParent);
						swap(pParent, pCur);
					}

					RotateR(grandParent);
					pParent->_color = BLACK;
					grandParent->_color = RED;
					break;
				}
			}
			//父亲节点为双亲的右节点
			else
			{
				pNode uncle = grandParent->_pLeft;
				//情况一,叔叔节点存在且为红
				if (uncle&&uncle->_color == RED)
				{
					pParent->_color = BLACK;
					uncle->_color = BLACK;
					grandParent->_color = RED;

					pCur = grandParent;   //继续向上调整
					pParent = pCur->_pParent;
				}

				//叔叔不存在或者存在且为黑
				else
				{
					//若是第三种情况转化为第二种
					if (pCur == pParent->_pLeft)
					{
						RotateR(pParent);
						swap(pParent, pCur);
					}

					RotateL(grandParent);
					pParent->_color = BLACK;
					grandParent->_color = RED;
				}
			}
		}
		_pRoot->_color = BLACK;
		return true;
	}

三、判断是否为红黑树
根据红黑树的性质,根节点为黑色;要满足任何一个路径黑色节点的个数相等, 我们可以分别统计每条黑色节点的个数,当相等时就判断是不是红黑树 ;以及有没有相邻的红色节点。

bool IsRBTree()
	{
		if (_pRoot == NULL)
			return true;
		if (_pRoot->_color == RED)  //根节点为红色
			return false;

		int blackNum = 0;  //黑色节点的个数
		int num = 0;     //任意路径的黑色节点个数
		pNode pCur = _pRoot;
		while (pCur)
		{
			if (pCur->_color == BLACK)
			{
				blackNum++;
			}
			pCur = pCur->_pLeft;
		}

		return _IsRBTree(_pRoot, blackNum, num);
	}
bool _IsRBTree(pNode pRoot, const int blackNum, int num)
	{
		if (NULL == pRoot)  //一条路径结束
		{
			if (num != blackNum)
			{
				return false;
			}
			else
			{
				return true;
			}
		}
		if (pRoot->_color == BLACK)
		{
			++num;
		}
		//两个相邻的红色节点
		if ((pRoot->_color == RED) && (pRoot->_pParent->_color == RED))
		{
			return false;
		}
		return _IsRBTree(pRoot->_pLeft, blackNum, num) && _IsRBTree(pRoot->_pRight, blackNum, num);
	}

完整代码如下:
#pragma once

enum COLOR
{
	BLACK,
	RED
};

template<class K, class V>
struct RBTreeNode
{
	RBTreeNode(const K& key, const V& value, COLOR color = RED)
	:_pLeft(NULL)
	, _pRight(NULL)
	, _pParent(NULL)
	, _key(key)
	, _value(value)
	, _color(color)
	{}

	RBTreeNode<K, V> *_pLeft;
	RBTreeNode<K, V> *_pRight;
	RBTreeNode<K, V> *_pParent;

	K _key;
	V _value;
	COLOR _color;
};

template<class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
	typedef Node* pNode;
public:
	RBTree()
		:_pRoot(NULL)
	{}

	bool Insert(const K& key, const V& value)
	{
		if (NULL == _pRoot)
		{
			_pRoot = new Node(key, value, BLACK);   //根节点为黑色
			return true;
		}

		//找插入位置
		pNode pCur = _pRoot;
		pNode pParent = NULL;

		while (pCur)
		{
			if (key < pCur->_key)
			{
				pParent = pCur;
				pCur = pCur->_pLeft;
			}
			else if (key > pCur->_key)
			{
				pParent = pCur;
				pCur = pCur->_pRight;
			}
			else
			{
				return false;
			}
		}

		pCur = new Node(key, value);
		if (key < pParent->_key)
			pParent->_pLeft = pCur;
		else
			pParent->_pRight = pCur;

		pCur->_pParent = pParent;

		//有可能会违反红黑树的性质---3
		while (pParent&&pParent->_color == RED)
		{
			pNode grandParent = pParent->_pParent;
			if (pParent == grandParent->_pLeft)
			{
				pNode uncle = grandParent->_pRight;
				//情况一,叔叔节点存在且为红
				if (uncle&&uncle->_color == RED)
				{
					pParent->_color = BLACK;
					uncle->_color = BLACK;
					grandParent->_color = RED;

					pCur = grandParent;   //继续向上调整
					pParent = pCur->_pParent;
				}

				//叔叔不存在或者存在且为黑
				else
				{
					//若是第三种情况转化为第二种
					if (pCur == pParent->_pRight)
					{
						RotateL(pParent);
						swap(pParent, pCur);
					}

					RotateR(grandParent);
					pParent->_color = BLACK;
					grandParent->_color = RED;
					break;
				}
			}
			//父亲节点为双亲的右节点
			else
			{
				pNode uncle = grandParent->_pLeft;
				//情况一,叔叔节点存在且为红
				if (uncle&&uncle->_color == RED)
				{
					pParent->_color = BLACK;
					uncle->_color = BLACK;
					grandParent->_color = RED;

					pCur = grandParent;   //继续向上调整
					pParent = pCur->_pParent;
				}

				//叔叔不存在或者存在且为黑
				else
				{
					//若是第三种情况转化为第二种
					if (pCur == pParent->_pLeft)
					{
						RotateR(pParent);
						swap(pParent, pCur);
					}

					RotateL(grandParent);
					pParent->_color = BLACK;
					grandParent->_color = RED;
				}
			}
		}
		_pRoot->_color = BLACK;
		return true;
	}

	bool IsRBTree()
	{
		if (_pRoot == NULL)
			return true;
		if (_pRoot->_color == RED)  //根节点为红色
			return false;

		int blackNum = 0;  //黑色节点的个数
		int num = 0;     //任意路径的黑色节点个数
		pNode pCur = _pRoot;
		while (pCur)
		{
			if (pCur->_color == BLACK)
			{
				blackNum++;
			}
			pCur = pCur->_pLeft;
		}

		return _IsRBTree(_pRoot, blackNum, num);
	}
	void InOrder()
	{
		if (NULL == _pRoot)
			return;
		_InOrder(_pRoot);
	}
private:
	bool _IsRBTree(pNode pRoot, const int blackNum, int num)
	{
		if (NULL == pRoot)  //一条路径结束
		{
			if (num != blackNum)
			{
				return false;
			}
			else
			{
				return true;
			}
		}
		if (pRoot->_color == BLACK)
		{
			++num;
		}
		//两个相邻的红色节点
		if ((pRoot->_color == RED) && (pRoot->_pParent->_color == RED))
		{
			return false;
		}
		return _IsRBTree(pRoot->_pLeft, blackNum, num) && _IsRBTree(pRoot->_pRight, blackNum, num);
	}
	//左单旋
	void RotateL(pNode pParent)
	{
		pNode pSubR = pParent->_pRight;
		pNode pSubRL = pSubR->_pLeft;

		//处理pSubR
		pParent->_pRight = pSubRL;
		if (pSubRL)
			pSubRL->_pParent = pParent;

		pSubR->_pLeft = pParent;
		pNode pPParent = pParent->_pParent;
		pSubR->_pParent = pPParent;
		pParent->_pParent = pSubR;

		//判断是否为根
		if (pParent == _pRoot)
			_pRoot = pSubR;
		//判断是左子树还是右子树
		else
		{
			if (pPParent->_pLeft == pParent)
				pPParent->_pLeft = pSubR;
			else
				pPParent->_pRight = pSubR;
		}
	}

	//右单旋
	void RotateR(pNode pParent)
	{
		pNode pSubL = pParent->_pLeft;
		pNode pSubLR = pSubL->_pRight;

		//处理pSubR
		pParent->_pLeft = pSubLR;
		if (pSubLR)
			pSubLR->_pParent = pParent;

		pSubL->_pRight = pParent;
		pNode pPParent = pParent->_pParent;
		pSubL->_pParent = pPParent;
		pParent->_pParent = pSubL;

		//判断是否为根
		if (pParent == _pRoot)
			_pRoot = pSubL;
		//判断是左子树还是右子树
		else
		{
			if (pPParent->_pLeft == pParent)
				pPParent->_pLeft = pSubL;
			else
				pPParent->_pRight = pSubL;
		}
	}

	void _InOrder(pNode pRoot)
	{
		if (pRoot)
		{
			_InOrder(pRoot->_pLeft);
			cout << "<" << pRoot->_key << "," << pRoot->_color << ">" << endl;
			_InOrder(pRoot->_pRight);
		}
	}
private:
	pNode _pRoot;
};

void RBTreeTest()
{
	int array[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
	RBTree<int, int> t;
	for (size_t i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		t.Insert(array[i], i);
	}
	t.InOrder();

	if (t.IsRBTree())
		cout << "是红黑树" << endl;
	else
		cout << "不是红黑树" << endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值