1 红黑树的概念

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red
Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路
径会比其他路径长出俩倍,因而是接近平衡的。(红黑树是接近平衡的,AVL树是绝对平衡,但两者的性能相近,AVL树的旋转比较多且复杂 ,红黑树相对简单)

红黑树是如何做到近似平衡的呢?这就与他的性质相关,具体如下:

1. 每个结点不是红色就是黑色。
2. 根节点是黑色的 。
3. 如果一个节点是红色的,则它的两个孩子结点是黑色的 。
4. 对于每个结点,从该结点到其所有后代叶结点的简单路径上,均 包含相同数目的黑色结点 。
5. 每个叶子结点都是黑色的(此处的叶子结点指的是空结点)也就是图中的NIL。

通过上述性质我们可以得出:

一条最短的路径就是只有黑节点的路径。而一条最长路径就是黑红相间的路径,这样就可以保证没有一条路径会比其他路径长出俩倍。

2.红黑树的插入

红黑树是在二叉搜索树的基础上加上其平衡限制条件,因此红黑树的插入可分为两步:
1. 按照二叉搜索的树规则插入新节点。
2.检测新节点插入后,红黑树的性质是否造到破坏。
这里重要的就是红黑树遭到破坏后如何进行调整。
1.首先我们要确保插入的节点的颜色是红色的。为什么要这样做呢? 这是因为如果插入的节点是黑色的会影响所有的路径,因为要保证每条路径上黑色节点的数目是一样的,插入的是红节点则只用看该路径是否满足红黑树的要求。
2.如果要插入的父亲节点存在且颜色是黑色的,则无需进行调整,因为满足红黑树的性质。
3.如果要插入的父亲节点存在且颜色是红色的,则需要进项调整,具体分为一下情况:

2.1.叔叔节点存在且为红

解决方式:将p,u改为黑,g改为红,然后把g当成cur,继续向上调整。

这里的a,b,c,d,e是可以变化的对应着各种复杂的情况。

等等还有很多种可能,但是他们对应的处理方式都是一样的。

2.2叔叔节点不存在或者叔叔节点存在且为黑

无论是叔叔节点不存在还是存在且为黑,他们的处理方法都是一样的,都是旋转加变色,旋转变色后就是一颗符合规则的红黑子树。这里的旋转是根据g,p,cur节点的位置进行旋转的。

3.代码实现

#pragma once
#include<iostream>
using namespace std;

enum Col
{
	BLACK,
	RED
};
template<class K,class V>
struct RBTreeNode
{

	RBTreeNode(const pair<K,V>& kv)
		:_parent(nullptr)
		,_left(nullptr)
		,_right(nullptr)
		,_kv(kv)
		,_col(RED)
	{}


	RBTreeNode<K, V>* _parent;
	RBTreeNode<K, V>* _left;
	RBTreeNode<K, V>* _right;

	pair<K, V>_kv;
	Col _col;
};

template<class K,class V>
class RBTree
{
	typedef RBTreeNode<K, V> Node;
public:
	bool insert(const pair<K, V>& kv)
	{
		if (_root == nullptr)
		{
			_root = new Node(kv);
			_root->_col = BLACK;
			return true;
		}

		Node* cur = _root;
		Node* parent = nullptr;

		while (cur)
		{
			if (cur->_kv.first > kv.first)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if(cur->_kv.first < kv.first)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;
			}
		}

		//找到要插入的位置 进行链接
		cur = new Node(kv);
		if (parent->_kv.first > kv.first)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		cur->_parent = parent;

		//进行调整 父亲节点存在且为红 才需要调整 默认插入的节点是红色的
		while (parent && parent->_col==RED)
		{
			Node* gradeparent = parent->_parent; //gradeparent节点一定存在 否则不会进入这里 直接就插入成功了
			if (parent == gradeparent->_left)
			{
				Node* uncle = gradeparent->_right;
				//叔叔节点存在且为红
				if (uncle && uncle->_col == RED)
				{
					//变色+继续向上调整
					uncle->_col = parent->_col = BLACK;
					gradeparent->_col = RED;

					//向上调整 此时parent相当于cur
					cur = gradeparent;
					parent = cur->_parent;
				}
				//叔叔节点不存在 or 叔叔节点存在为黑
				else 
				{
					//旋转加变色
					if (cur == parent->_left)
					{
						//    g
						//  p
						//c
						RotateR(gradeparent);
						parent->_col = BLACK;
						gradeparent->_col = RED;
					}
					else
					{
						//    g
						//  p
						//    c

						RotateL(parent);
						RotateR(gradeparent);
						cur->_col = BLACK;
						gradeparent->_col = RED;
					}

					break;
				}
				
			}
			else
			{
				Node* uncle = gradeparent->_left;

				//叔叔存在且为红
				if (uncle && uncle->_col == RED)
				{
					//变色+向上调整
					uncle->_col = parent->_col = BLACK;
					gradeparent->_col = RED;

					cur = gradeparent;
					parent = cur->_parent;
				}
				//叔叔不存在 or 叔叔存在且为黑
				else
				{
					//旋转+变色
					if (cur == parent->_right)
					{
						//g
						//  p
						//    c

						RotateL(gradeparent);

						parent->_col = BLACK;
						gradeparent->_col = RED;
					}
					else
					{
						//g
						//  p
						//c

						RotateR(parent);
						RotateL(gradeparent);

						cur->_col = BLACK;
						gradeparent->_col = RED;
					}

					break;
				}

			}
		}
		_root->_col = BLACK;
		return true;
	}

	void RotateR(Node* parent)
	{
		Node* cur = parent->_left;
		Node* curRight = cur->_right;
		Node* ppNode = parent->_parent;

		//进行链接
		parent->_left = curRight;
		if (curRight)
			curRight->_parent = parent;

		cur->_right = parent;
		parent->_parent = cur;

		if (ppNode == NULL)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = cur;
			}
			else
			{
				ppNode->_right = cur;
			}
			cur->_parent = ppNode;
		}
	}

	void RotateL(Node* parent)
	{
		Node* cur = parent->_right;
		Node* curLeft = cur->_left;
		Node* ppNode = parent->_parent;
		parent->_right = curLeft;
		if (curLeft)
		{
			curLeft->_parent = parent;
		}
		cur->_left = parent;
		parent->_parent = cur;
		if (ppNode == nullptr)
		{
			_root = cur;
			cur->_parent = nullptr;
		}
		else
		{
			if (ppNode->_left == parent)
			{
				ppNode->_left = cur;
			}
			else
			{
				ppNode->_right = cur;
			}
			cur->_parent = ppNode;
		}
	}

	bool CheckColour(Node* root, int blacknum, int benchmark)
	{
		if (root == nullptr)
		{
			if (blacknum != benchmark)
				return false;

			return true;
		}

		if (root->_col == BLACK)
		{
			++blacknum;
		}

		if (root->_col == RED && root->_parent && root->_parent->_col == RED)
		{
			cout << root->_kv.first << "出现连续红色节点" << endl;
			return false;
		}

		return CheckColour(root->_left, blacknum, benchmark)
			&& CheckColour(root->_right, blacknum, benchmark);
	}

	bool IsBalance()
	{
		return IsBalance(_root);
	}

	bool IsBalance(Node* root)
	{
		if (root == nullptr)
			return true;

		if (root->_col != BLACK)
		{
			return false;
		}

		// 基准值
		int benchmark = 0;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_col == BLACK)
				++benchmark;

			cur = cur->_left;
		}

		return CheckColour(root, 0, benchmark);
	}

private:
	Node* _root = nullptr;
};
#include"RBTree.h"

int main()
{
	int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
	RBTree<int, int> t;
	for (auto e : a)
	{
		t.insert(make_pair(e, e));
		cout << "Insert:" << e << "->" << t.IsBalance() << endl;
	}

	return 0;
}

更多推荐