数据结构--红黑树

数据结构之红黑树

 

一.什么是红黑树?

红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结点的颜色,可以是red或者black,通过对任何一条从根节点到叶子结点上的简单路径来约束,红黑树保证最长路径不超过最短路径的两倍,因而近似平衡。

 

二.红黑树满足的条件?

1. 每个结点不是红色就是黑色

2. 根节点是黑色的

3. 如果一个根节点是红色的,则它的两个叶子结点是黑色的(没有两个连续的红色结点)

4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相同数目的黑色结点(每条路径上黑色结点的数量相等)

 

三.红黑树的插入操作详解

 

红黑树的情况分类

 

【情况一】

cur为红,p为红,g为黑,u存在且为红

则将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

【情况二】

cur为红,p为红,g为黑,u不存在/u为黑

p为g的左孩子,cur为p的左孩子,则进行右单旋转;相反,p为g的右孩子,cur

为p的右孩子,则进行左单旋转

p、g变色--p变黑,g变红

【情况三】

cur为红,p为红,g为黑,u不存在/u为黑

p为g的左孩子,cur为p的右孩子,则针对p做左单旋转;相

反,p为g的右孩子,cur为p的左孩子,则针对p做右单旋转

则转换成了情况2

具体如下图:



左单旋以及右单旋操作请见平衡二叉树:http://blog.csdn.net/sayhello_world/article/details/70231643

 

判断此树是否为平衡二叉树:

要满足上述条件

0.      如果根为空则就为平衡二叉树

1.      两个红色结点不能相连

2.      从根节点到任意叶子节点的黑色结点数目必须相同

	bool CheckRBTree()
	{
		if (_pRoot == NULL)
			return true;

		if (_pRoot->_color == RED)
		{	
			cout << "根为红色不满足" << endl;
			return false;
		}

		//计算黑色结点的个数 应该每一条路径上数目都相同
		int BlackCount = 0;
		Node* pCur = _pRoot;
		//只走最左边的那一条路
		while (pCur)
		{
			if (pCur->_color == BLACK)
				BlackCount++;
			pCur = pCur->_pLeft;
		}
		int k = 0;
		return _CheckRBTree(_pRoot,BlackCount,k);
	}

	bool _CheckRBTree(Node* pRoot,const size_t blackCount,size_t k)
	{
		if (pRoot == NULL)
			return true;

		//如果两个连续的红色 就违反规则
		Node* Parent = pRoot->_pParent;
		if (Parent && Parent->_color == RED && pRoot->_color == RED)
		{
			cout << "两个红色不能相连接" << endl;
			return false;
		}

		//判断是否k=blackCount
		//如果此时为黑色结点 k要++
		if (pRoot->_color == BLACK)
			k++;
		
		if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
		{
			if (k != blackCount)
			{
				cout << "违反两个黑色结点应该相同原则" << endl;
				return false;
			}
		}

		return _CheckRBTree(pRoot->_pLeft, blackCount, k) && _CheckRBTree(pRoot->_pRight, blackCount, k);
	}


总代码:

BRTree.cpp

#pragma once  


#include <iostream>  
using namespace std;


enum Color
{
	RED,
	BLACK
};


template<class K, class V>
struct RBTreeNode
{
public:
	RBTreeNode(const V&value, const K& key)
		:_value(value)
		, _key(value)
		, _pLeft(NULL)
		, _pRight(NULL)
		, _pParent(NULL)
		, _color(RED)//初始化为红色结点  
	{}


	V _value;
	K _key;
	RBTreeNode<K, V>* _pLeft;
	RBTreeNode<K, V>* _pRight;
	RBTreeNode<K, V>* _pParent;
	Color _color;
};


template < class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:


	RBTree()
		:_pRoot(NULL)
	{}


	bool Insert(const K& key, const V& value)
	{
		//判断根节点是否为空  
		if (NULL == _pRoot)
		{
			_pRoot = new Node(key, value);
			return false;
		}


		Node* pCur = _pRoot;
		Node* pParent = NULL;
		//找插入位置  
		while (pCur)
		{
			if (key > pCur->_key)
			{
				pParent = pCur;
				pCur = pCur->_pRight;
			}
			else if (key < pCur->_key)
			{
				pParent = pCur;
				pCur = pCur->_pLeft;
			}
			else
				return false;
		}


		//插入结点  
		pCur = new Node(key, value);
		if (key < pParent->_key)
			pParent->_pLeft = pCur;
		else if (key > pParent->_key)
			pParent->_pRight = pCur;


		pCur->_pParent = pParent;


		//对结点的颜色进行处理  
		//从下往上修改颜色 到根节点且根节点为红结束  
		while (_pRoot != pCur && pParent->_color == RED)
		{
			Node* grandFather = pParent->_pParent;
			if (pParent == grandFather->_pLeft)
			{
				Node* uncle = grandFather->_pRight;
				//当前插得为红,双亲为红,叔叔也为红  
				//此时应该把祖先变为红,把双亲叔叔变为黑  
				if (uncle && uncle->_color == RED)
				{
					grandFather->_color = RED;
					pParent->_color = BLACK;
					uncle->_color = BLACK;


					pCur = grandFather;
					pParent = pCur->_pParent;
				}
				//否则叔叔不存在 或者叔叔为黑  
				else
				{
					//如果cur在父母的右边 则左单旋 再右单旋  
					if (pParent->_pRight == pCur)
					{
						RotateLeft(pParent);
						std::swap(pParent, pCur);
					}
					//否则只右单旋  
					pParent->_color = BLACK;
					grandFather->_color = RED;
					RotateRight(grandFather);
				}
			}
			//否则父母结点在祖先节点的右边  
			else
			{
				Node* uncle = grandFather->_pLeft;
				if (uncle && uncle->_color == RED)
				{
					pParent->_color = BLACK;
					uncle->_color = BLACK;
					grandFather->_color = RED;


					pCur = grandFather;
					pParent = pCur->_pParent;
				}
				else
				{
					if (pCur == pParent->_pLeft)
					{
						RotateRight(pParent);
						std::swap(pParent, pCur);
					}
					grandFather->_color = RED;
					pParent->_color = BLACK;
					RotateLeft(grandFather);
				}
			}
		}
		//最后要把根节点换成黑色的  
		_pRoot->_color = BLACK;
		return true;
	}


	bool CheckRBTree()
	{
		if (_pRoot == NULL)
			return true;


		if (_pRoot->_color == RED)
		{
			cout << "根为红色不满足" << endl;
			return false;
		}


		//计算黑色结点的个数 应该每一条路径上数目都相同  
		int BlackCount = 0;
		Node* pCur = _pRoot;
		//只走最左边的那一条路  
		while (pCur)
		{
			if (pCur->_color == BLACK)
				BlackCount++;
			pCur = pCur->_pLeft;
		}
		int k = 0;
		return _CheckRBTree(_pRoot, BlackCount, k);
	}


	bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)
	{
		if (pRoot == NULL)
			return true;


		//如果两个连续的红色 就违反规则  
		Node* Parent = pRoot->_pParent;
		if (Parent && Parent->_color == RED && pRoot->_color == RED)
		{
			cout << "两个红色不能相连接" << endl;
			return false;
		}


		//判断是否k=blackCount  
		//如果此时为黑色结点 k要++  
		if (pRoot->_color == BLACK)
			k++;


		if (pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
		{
			if (k != blackCount)
			{
				cout << "违反两个黑色结点应该相同原则" << endl;
				return false;
			}
		}


		return _CheckRBTree(pRoot->_pLeft, blackCount, k) && _CheckRBTree(pRoot->_pRight, blackCount, k);
	}


	void InOrder()
	{
		_InOrder(_pRoot);
	}


private:


	void _InOrder(Node* pRoot)
	{
		if (pRoot == NULL)
			return;
		_InOrder(pRoot->_pLeft);
		cout << pRoot->_key << "  ";
		_InOrder(pRoot->_pRight);
	}


	void RotateLeft(Node*& pRoot)
	{
		Node* SubR = pRoot->_pRight;
		Node* SubRL = SubR->_pLeft;
		pRoot->_pRight = SubRL;


		if (SubRL)
			SubRL->_pParent = pRoot;
		SubR->_pLeft = pRoot;
		SubR->_pParent = pRoot->_pParent;
		
		pRoot->_pParent = SubR;
		pRoot = SubR;


		if (pRoot->_pParent == NULL)
			_pRoot = pRoot;
		else if (pRoot->_pParent->_key > pRoot->_key)
			pRoot->_pParent->_pLeft = pRoot;
		else if (pRoot->_pParent->_key < pRoot->_key)
			pRoot->_pParent->_pRight = pRoot;
	}


	void RotateRight(Node*& pRoot)
	{
		Node* SubL = pRoot->_pLeft;
		Node* SubLR = SubL->_pRight;
		pRoot->_pLeft = SubLR;
		if (SubLR)
			SubLR->_pParent = pRoot;
		SubL->_pRight = pRoot;
		SubL->_pParent = pRoot->_pParent;


		pRoot->_pParent = SubL;
		pRoot = SubL;


		if (pRoot->_pParent == NULL)
			_pRoot = pRoot;
		else if (pRoot->_pParent->_key > pRoot->_key)
			pRoot->_pParent->_pLeft = pRoot;
		else if (pRoot->_pParent->_key < pRoot->_key)
			pRoot->_pParent->_pRight = pRoot;
	}


private:
	Node* _pRoot;
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值