红黑树

一、概念

红黑树是一棵二叉搜索树,它在每个结点上增加了一个存储位来表示结

点的颜色,可以是red或者black,通过对任何一条从根节点到叶子结点上

的简单路径来约束,红黑树保证最长路径不超过最短路径的两倍,因而近视

平衡。

二、性质

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

2. 根节点是黑色的

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

的红色结点)

4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均包含相

同数目的黑色结点(每条路径上黑色结点的数量相等)

5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)

思考:

为什么满足上面的颜色约束性质,红黑树能保证最长路径不超过最短路径的两

倍?

三、插入实现

注意:cur为当前节点,p为父节点,g为祖父节点,u为叔叔节点

【情况一】

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

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

 

【情况二】

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

pg的左孩子,curp的左孩子,则进行右单旋转;相反,pg的右孩子,cur

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

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


【情况三】

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

pg的左孩子,curp的右孩子,则针对p做左单旋转;相

反,pg的右孩子,curp的左孩子,则针对p做右单旋转

则转换成了情况2



四、源码实现:

RBTree.h

#pragma once
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
enum Color
{
	RED,
	BLACK
};
template<class K, class V>
struct RBTreeNode
{
	RBTreeNode(const K& key, const V& value, Color color = RED)
	:_value(value)
	, _key(key)
	, _pLeft(NULL)
	, _pRight(NULL)
	, _pParent(NULL)
	, _color(color)
	{}

	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()
		:_pHead(NULL)
	{
		_pHead = new Node(0, 0);
		_pHead->_pLeft = _pHead;
		_pHead->_pRight = _pHead;

	}
	Node *GetMaxNode()
	{
		Node* pCur = GetRoot();
		while (pCur->_pRight)
			pCur = pCur->_pRight;
		return pCur;
	}
	Node *GetMinNode()
	{
		Node* pCur = GetRoot();
		while (pCur->_pLeft)
			pCur = pCur->_pLeft;
		return pCur;
	}
	bool Insert(const K& key, const V& value)
	{
		Node*& pRoot = GetRoot();
		if (pRoot == NULL)      // 当一个节点也没有时
		{
			pRoot = new Node(key, value);
			pRoot->_color = BLACK;
			pRoot->_pParent = _pHead;
			return true;
		}
		Node* pCur = pRoot;
		Node* pParent = NULL;
		while (pCur)
		{
			if (key < pCur->_key)
			{
				pParent = pCur;
				pCur = pCur->_pLeft;
			}
			else if (key == pCur->_key)//若已存在,返回false
			{
				return false;
			}
			else
			{
				pParent = pCur;
				pCur = pCur->_pRight;
			}
		}
		pCur = new Node(key, value);
		if (key < pParent->_key)
		{
			pParent->_pLeft = pCur;
			pCur->_pParent = pParent;
		}
		else
		{
			pParent->_pRight = pCur;
			pCur->_pParent = pParent;
		}
		//调整颜色
		while (pCur != pRoot && pParent->_color == RED)
		{
			Node* garndFather = pParent->_pParent;
			Node* uncle = NULL;
			if (pParent == garndFather->_pRight)
			{
				uncle = garndFather->_pLeft;
			}
			else
				uncle = garndFather->_pRight;
			if (uncle != NULL&&uncle->_color == RED)
			{
				pParent->_color = BLACK;
				uncle->_color = BLACK;
				garndFather->_color = RED;
			}
			else   //uncle不存在或uncle为黑
			{
				if (pParent == garndFather->_pLeft) //父亲是爷爷的左孩子
				{
					if (pCur = pParent->_pRight)
					{
						RotateLeft(pParent);
						swap(pParent, pCur);
					}
					if (pCur = pParent->_pLeft)
					{
						RotateRight(garndFather);
						pParent->_color = BLACK;
						garndFather->_color = RED;
					}
				}
				else                //父亲是爷爷的右孩子
				{
					if (pCur = pParent->_pLeft)
					{
						RotateRight(pParent);
						swap(pParent, pCur);
					}
					if (pCur = pParent->_pRight)
					{
						RotateLeft(garndFather);
						pParent->_color = BLACK;
						garndFather->_color = RED;
					}
				}
			}
			pCur = garndFather;
			pParent = pCur->_pParent;
		}
		_pHead->_pLeft = GetMinNode();
		_pHead->_pRight = GetMaxNode();
		pRoot->_color = BLACK;
		return true;
	}
	void RotateLeft(Node* parent)
	{
		Node* pparent = parent->_pParent;
		Node* subR = parent->_pRight;
		Node* subRL = subR->_pLeft;
		if (pparent == _pHead)
		{
			Node*& pRoot = GetRoot();
			pRoot = subR;
		}
		else
		{
			if (parent == pparent->_pLeft)
			{
				pparent->_pLeft = subR;
			}
			else
			{
				pparent->_pRight = subR;
			}
		}
		subR->_pParent = pparent;
		parent->_pParent = subR;
		parent->_pRight = subRL;
		if (subRL != NULL)
		{
			subRL->_pParent = parent;
		}
	}
	void RotateRight(Node* parent)
	{
		Node* subL = parent->_pLeft;
		Node* subLR = subL->_pRight;
		Node* pparent = parent->_pParent;
		if (pparent == _pHead)
		{
			Node*& pRoot = GetRoot();
			pRoot = subL;
		}
		else
		{
			if (parent = pparent->_pLeft)
			{
				pparent->_pLeft = subL;
			}
			else
			{
				pparent->_pRight = subL;
			}

		}
		subL->_pParent = pparent;
		subL->_pRight = parent;
		parent->_pParent = subL;
		parent->_pLeft = subLR;
		if (subLR != NULL)
		{
			subLR->_pParent = parent;
		}
	}
	void InOrder()
	{
		Node*& pRoot = GetRoot();
		_InOrder(pRoot);
	}
	void _InOrder(Node* pRoot)
	{
		if (pRoot)
		{
			_InOrder(pRoot->_pLeft);
			cout << pRoot->_key << " ";
			_InOrder(pRoot->_pRight);
		}
	}
	bool CheckRBTree()
	{
		Node*& pRoot = GetRoot();
		if (pRoot == NULL)
		{
			return true;
		}
		if (pRoot->_color == RED)
		{
			return false;
		}
		//找到一条路径上黑色节点的个数
		size_t blackCount = 0;
		Node* pCur = pRoot;
		while (pCur)
		{
			if (pCur->_color == BLACK)
			{
				blackCount++;
			}
			pCur = pCur->_pLeft;
		}
		size_t k = 0;
		return _CheckRBTree(pRoot, blackCount, k);
	}
	//每一条路径上的黑色节点相同时才是红黑树
	bool _CheckRBTree(Node* pRoot, const size_t blackCount, size_t k)//k一定为值传递
	{
		if (pRoot == NULL)
		{
			return true;
		}
		//当出现两个连续的红色节点的时候,可以确定不是红黑树
		if (pRoot->_pParent&&pRoot->_color == RED&&pRoot->_pParent->_color == RED)
		{
			return false;
		}
		//若是黑节点,k++
		if (pRoot->_color == BLACK)
		{
			k++;
		}
		//若是叶子节点,判断k和blackCount是否相等
		if (pRoot->_pLeft == NULL&&pRoot->_pRight == NULL)
		{
			if (k != blackCount)
			{
				return false;
			}
		}
		return _CheckRBTree(pRoot->_pLeft, blackCount, k);
	}
private:
	Node* _pHead;  	//红黑树加上一个头结点进行迭代器操作
	//(头结点的左孩子指向红黑树的最小值,右孩子指向最大值,parent域指向根节点)
private:
	Node* & GetRoot()
	{
		return _pHead->_pParent;
	}
};

RBTree.cpp

#include"RBTree.h"
void Test()
{
	int a[] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
	RBTree<int, int> bt;
	for (size_t idx = 0; idx < sizeof(a) / sizeof(a[0]); ++idx)
	{
		bt.Insert(a[idx], a[idx]);
	}
	bt.InOrder();
	cout << endl;
	cout << bt.CheckRBTree() << endl;
}
int main()
{
	Test();
	system("pause");
	return 0;
}

五、红黑树和AVL树的比较

红黑树和AVL树都是高效的平衡二叉树,增删查改的时间复杂度都是

O(lg(N))

红黑树的不追求完全平衡,保证最长路径不超过最短路径的2倍,相对而

言,降低了旋转的要求,所以性能跟AVL树差不多,但是红黑树实现更简

单,所以实际运用中红黑树更多。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值