红黑树的实现与验证--C++


红黑树的实现与验证–C++

红黑树实例:

《红黑树的实现与验证--C++》

在说红黑树之前,我们先来认识一下它:

首先强调一点:红黑树也是二叉搜索树。那么它就满足二叉搜索树的性质,除此之外,他还有几个比较特殊的性质,了解这些,有助于我们后面的分析

性质:

1、红黑树所有的节点都有颜色(红或黑)

2、红黑树的根结点是黑色的

3、红黑树的两个红色节点不能相连

4、红黑树的每一条链的黑节点的个数相同

5、所有空的节点都是黑色的

知道了这些之后开始进入红黑树的创建:

显然这就是红黑树的插入操作的编写了,那么要想将一个节点插入红黑树中,首先你得判断红黑树是不是空的,如果是空的,那么直接就可以插入;不是空的,那么得找插入位置,然后再插入,这一点和二叉搜索树的插入是一样的。不过需要注意,最后把根结点置成黑色的

插入?

插入的节点我们都默认为红色的,但是性质3说,红色的节点不能相链,如果,之后我们不管的话,性质3肯定不会满足的,所以我们需要对红黑树进行调解,让其满足这些性质。那么我们就需要分情况讨论了,我们重点分析一下,两个红色节点相链的情况怎么处理。

总共可以分为3种情况:

情况一

双亲结点为红色,祖先结点为黑色, 叔叔节点存在,且为红色

《红黑树的实现与验证--C++》

其实这个图里包含了四种情况,我只是将其中的一种情况中的转化后的形式画了出来,其他的也一样。

情况二

双亲结点为红色,祖先结点为黑色,叔叔节点不存在或存在为黑色

《红黑树的实现与验证--C++》

这种情况是:双亲在祖先节点的左的同时pCur在双亲的左;或是双亲在祖先节点的右的同时,pCur在双亲的右。

这样我们就可以进行单旋处理,根据情况调用左单旋还是右单旋。

情况三

双亲结点为红色,祖先结点为黑色,叔叔节点不存在或存在为黑色

《红黑树的实现与验证--C++》

这个和情况二是互补的,情况二中剩下的都是不能单旋直接处理的,那么就需要双旋,图中画的是左右双旋,先左旋之后,我们发现,和情况二的一样,那么代码中这一块就可以放在一起处理。

不过,这里需要注意一点,就是,左旋之后只想pCur变成了双亲,而parent变成了孩子,所以,在第一次旋转之后先对这两个指针进行交换,在进行第二次旋转。

验证?

最后将插入写完之后,我们可以写一个函数来测试一下这个是不是红黑树,这个其实也是对红黑树的性质的检验。其中重点验证性质3和性质4。那么我们来分析一下这步骤:

1、判断这个树是不是空树,是的话,直接返回true

2、验证性质2,判断根结点的颜色是不是黑色的,是,返回true

3、要验证性质三,得遍历整个树,而性质4的验证也要这莫做,那么我们将这两个一起验证。那么首先我们得求出一条链的黑色节点的个数,并将其保存起来,再递归遍历左右子树,验证。

代码?

#include<iostream>
using namespace std;

enum COLOR { RED, BLACK };

template<class K, class V>
struct RBTreeNode
{
	RBTreeNode<K, V>* _pLeft;
	RBTreeNode<K, V>* _pRight;
	RBTreeNode<K, V>* _pParent;
	K _key;
	V _value;
	COLOR _color;

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

template<class K, class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
private:
	Node* _pRoot;
public:
	RBTree() :_pRoot(NULL) {}
	bool Insert(const K& key, const V&value);
	void _RotateL(Node* parent);
	void _RotateR(Node* parent);
	void InOrder();
	void _InOrder(Node* pRoot);
	bool CheckRBTree();
	bool _CheckRBTree(Node* pRoot,int counter,int k);

};

//插入节点
template<class K, class V>bool RBTree<K, V>::Insert(const K&key, const V&value)
{
	//创建根节点
	if (_pRoot == NULL)
	{
		_pRoot = new Node(key, value);
		_pRoot->_color = BLACK;
		return true;
	}

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

	pCur->_pParent = parent; //注意

	//看红黑树是否满足性质,分情况讨论
	while (_pRoot != pCur&&pCur->_pParent->_color == RED)
	{
		Node* gf = parent->_pParent; //双亲的双亲,肯定存在,不然不会进入这个循环

		//双亲在左,叔叔(存在的话)在右
		if (gf->_pLeft == parent)
		{
			Node* uncle = gf->_pRight;
			if (uncle&&uncle->_color == RED) //情况一
			{
				parent->_color = BLACK;
				uncle->_color = BLACK;
				gf->_color = RED;

				//向上更新
				pCur = gf;
				parent = pCur->_pParent;
			}
			else //情况二,三(将三转化为二,再一起处理)
			{
				if (parent->_pRight == pCur)
				{
					_RotateL(parent);
					std::swap(parent, pCur);
				}

				gf->_color = RED;
				parent->_color = BLACK;
				_RotateR(gf);
			}
		}
		else//双亲在右
		{
			Node*uncle = gf->_pLeft;
			if (uncle && uncle->_color == RED)  //情况一
			{
				parent->_color = BLACK;
				uncle->_color = BLACK;
				gf->_color = RED;

				//向上更新
				pCur = gf;
				parent = pCur->_pParent;
			}
			else   //情况二、三(将情况三转化为情况二,再一起处理)
			{
				if (parent->_pLeft == pCur)
				{
					_RotateR(parent);
					std::swap(parent, pCur);
				}

				gf->_color = RED;
				parent->_color = BLACK;
				_RotateL(gf);
			}
		}
	}

	_pRoot->_color = BLACK;
	return true;
}

//左旋
template<class K, class V>void RBTree<K, V>::_RotateL(Node* parent)
{
	Node* subR = parent->_pRight;
	Node* subRL = subR->_pLeft;   //可能不存在

	parent->_pRight = subRL;
	if (subRL)
		subRL->_pParent = parent;

	subR->_pLeft = parent;
	Node* gparent = parent->_pParent; 
	parent->_pParent = subR;
	subR->_pParent = gparent;

	if (gparent == NULL) //parent是根节点
		_pRoot = subR;
	else if (gparent->_pLeft == parent)
		gparent->_pLeft = subR;
	else
		gparent->_pRight = subR;

}

//右旋
template<class K, class V>void RBTree<K, V>::_RotateR(Node* parent)
{
	Node* subL = parent->_pLeft;
	Node* subLR = subL->_pRight;

	parent->_pLeft = subLR;
	if (subLR)
		subLR->_pParent = parent;

	subL->_pRight = parent;
	Node* gparent = parent->_pParent;
	parent->_pParent = subL;
	subL->_pParent = gparent;

	if (gparent == NULL)
		_pRoot = subL;
	else if (gparent->_pLeft == parent)
		gparent->_pLeft = subL;
	else
		gparent->_pRight = subL;
}

template<class K, class V>void RBTree<K, V>::InOrder()
{
	cout << "InOrder:  ";
	_InOrder(_pRoot);
	cout << endl;
}

template<class K, class V>void RBTree<K, V>::_InOrder(Node* pRoot)
{
	if (pRoot)
	{
		_InOrder(pRoot->_pLeft);
		cout << pRoot->_key << "  ";
		_InOrder(pRoot->_pRight);
	}
}

template<class K, class V>bool RBTree<K, V>::CheckRBTree()
{
	if (_pRoot == NULL)
		return true;
	if (_pRoot->_color == RED) // 违反性质2“根结点为黑色
		return false;
	int blackcount = 0;  //统计一条链上黑色结点的个数

	Node* pCur = _pRoot;
	while (pCur)
	{
		if (pCur->_color == BLACK)
			blackcount++;
		pCur = pCur->_pLeft;     //这里以最左边的那一条链为例
	}
	//验证性质4“每条链上的黑色结点都相等”,验证性质3“红色结点不能相连”
	return _CheckRBTree(_pRoot, blackcount, 0);
}

template<class K, class V>bool RBTree<K, V>::_CheckRBTree(Node* pRoot, int counter, int k)
{
	if (pRoot == NULL)
		return true;
	if (pRoot->_color == BLACK)
		k++;

	Node* parent = pRoot->_pParent;
	if (parent && parent->_color == RED && pRoot->_color == RED)  //违反性质3“红色结点不能相连”
		return false;

	if (pRoot == NULL)
	{
		if (k != counter)  //违反性质4“每条链上的黑色结点都相等”
			return false;
	}

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

void TestRBTree()
{
	int a[] = { 10, 7, 8, 15, 5, 6, 11, 13, 12 };
	//int a[] = { 16,3,7,9,11,26,18,14 };
	//int a[] = { 3,7,5,8,4,2,9,0 };


	RBTree<int, int> t;
	cout << "NotOrder: ";
	for (int index = 0; index < sizeof(a) / sizeof(a[0]); index++)
	{
		cout << a[index] << "  ";
		t.Insert(a[index], index);
	}
	cout << endl;
	t.InOrder();
	if (t.CheckRBTree())
		cout << "是红黑树!" << endl;
	else
		cout << "不是红黑树!" << endl;
}

int main()
{
	TestRBTree();
	return 0;
}

    原文作者:算法小白
    原文地址: https://blog.csdn.net/qq_34777600/article/details/79477750
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞