【C++】红黑树的调整

红黑树(Red-Black Tree)是一种自平衡的二叉搜索树,通过颜色约束 + 旋转 + 变色 来保证树的高度始终为 O(logn)。插入和删除后可能破坏红黑性质,需进行调整(fixup)

红黑树要满足以下几个条件:

  1. 根节点为黑色
  2. 红色节点的孩子必须是黑色节点
  3. 任意一条路径上的黑色节点数量相等
  4. 最长路径上的节点数量不超过最短路径节点数量的两倍

接下来就来详细介绍红黑树旋转 + 变色的几种情况。

一、叔节点 u 是 红色

cpp 复制代码
       g(B)                g(R)
      /    \              /    \
   p(R)    u(R)   →    p(B)    u(B)
   /                   /
 z(R)               z(R)

这时只需要将grandpa变为红色,parent和uncle介蒂安变为黑色。由于grandpa节点变成红色,此时需要继续向上检查。

二、叔节点为黑色或为空

在这种情况下就会变得复杂得多,涉及到旋转和变色。

2.1、RR型

cpp 复制代码
   g(B)                     p(B)
  /    \                   /    \
u(B)  p(R)      →       g(R)   z(R)
        \               /
       z(R)          u(B)

叔节点为黑色或为空时,在RR型中需要将grandpa节点进行左旋,并且将parent节点变成黑色grandpa节点变成红色。注意这里由于parent节点已经变成黑色,不需要再向上进行调整。

2.2、RL型

cpp 复制代码
   g(B)                g(B)                   z(B)
  /    \              /    \                 /    \
u(B)  p(R)   →      u(B)  z(R)    →       g(R)   p(R)
      /                       \            /
    z(R)                     p(R)       u(B)

叔节点为黑色或为空时,在RL型中需要先将parent节点进行右旋转化为RR型,再对grandpa节点进行左旋。同时z节点变成黑色,grandpa节点变成红色。

2.3、LL型

cpp 复制代码
       g(B)                 p(B)
      /    \               /    \
   p(R)    u(B)   →     z(R)   g(R)
   /                             \
 z(R)                           u(B)

叔节点为黑色或为空时,在LL型中需要将grandpa节点进行右旋,并且将parent节点变成黑色grandpa节点变成红色。注意这里由于parent节点已经变成黑色,不需要再向上进行调整。

2.4、LR型

cpp 复制代码
       g(B)                  g(B)                 z(B)
      /    \                /    \               /    \
   p(R)    u(B)   →      z(R)    u(B)   →    p(R)   g(R)
      \                  /                          \
     z(R)             p(R)                        u(B)

叔节点为黑色或为空时,在LR型中需要先将parent节点进行左旋转化为LL型,再对grandpa节点进行右旋旋。同时z节点变成黑色,grandpa节点变成红色。

三、旋转与变色总结

叔叔颜色 当前节点位置 操作
Case 1 红色 任意 变色(p, u → 黑;g → 红),继续向上
Case 2 黑色 外侧(LL/RR) 单旋 + 变色(p 与 g 交换颜色)
Case 3 黑色 内侧(LR/RL) 双旋 + 变色(先转外侧,再单旋)

四、代码实现

cpp 复制代码
#include<iostream>

using namespace std;
enum color
{
	RED, BLACK
};

template<class T>
class RBNode {
public:
	RBNode(const T& val=T()):
		date(val),
		_parent(nullptr),
		_left(nullptr),
		_right(nullptr),
		col(RED)
	{

	}
	T date;
	RBNode<T>* _parent;
	RBNode<T>* _left;
	RBNode<T>* _right;
	color col;
};

template<class T>
class RBTree {
public:
	typedef RBNode<T> Node;
	RBTree():_root(nullptr){}



	void insert(const T& x)
	{
		//插入节点
		Node* cur = _root, * parent = nullptr, * nn = new Node(x);
		while (cur)
		{
			parent = cur;
			if (x < cur->date) { cur = cur->_left; }
			else
			{
				cur = cur->_right;
			}
		}
		if (parent == nullptr)//如果是空树
		{
			_root = nn;
		}
		else
		{
			nn->_parent = parent;
			if (nn->date < parent->date) parent->_left = nn;
			else
			{
				parent->_right = nn;
			}
			cur = nn;
		}

		//修善红黑树
		while (parent && parent->col == cur->col && cur->col == RED)
		{
			Node* uncle;
			Node* grandpa = parent->_parent;
			if (grandpa)
			{
				if (parent == grandpa->_left)
				{
					uncle = grandpa->_right;
					if (uncle && uncle->col == RED)//uncle是红色
					{
						grandpa->col = RED;
						parent->col = uncle->col = BLACK;
						cur = grandpa;
						parent = cur->_parent;
						if (parent) grandpa = parent->_parent;
						else
						{
							grandpa = nullptr;
						}
					}
					else
					{
						if (cur == parent->_left)
						{
							rotateRight(grandpa);
							parent->col = BLACK;
							grandpa->col = RED;
						}
						else
						{
							rotateLeft(parent);
							rotateRight(grandpa);
							cur->col = BLACK;
							grandpa->col = RED;
						}
						break;
					}
				}
				else
				{
					uncle = grandpa->_left;
					if (uncle && uncle->col == RED)//uncle是红色
					{
						grandpa->col = RED;
						grandpa->col = RED;
						parent->col = uncle->col = BLACK;
						cur = grandpa;
						parent = cur->_parent;
						if (parent) grandpa = parent->_parent;
						else
						{
							grandpa = nullptr;
						}
					}
					else
					{
						if (cur == parent->_right)
						{
							rotateLeft(grandpa);
							parent->col = BLACK;
							grandpa->col = RED;
						}
						else
						{
							rotateRight(parent);
							rotateLeft(grandpa);
							cur->col = BLACK;
							grandpa->col = RED;
						}
						break;
					}
				}

			}
		}
		_root->col = BLACK;//根节点常置为black
	}

	void rotateLeft(Node* node)
	{
		Node* parent = node->_parent, * rc = node->_right, * rlc = node->_right->_left;
		node->_right = rlc;
		if (rlc) rlc->_parent = node;
		rc->_left =node;
		node->_parent = rc;
		if (parent == nullptr)
		{
			rc->_parent = nullptr;
			_root = rc;
		}
		else
		{
			rc->_parent = parent;
			if (parent->_left == node)
			{
				parent->_left = rc;
			}
			else
			{
				parent->_right = rc;
			}
		}
	}

	void rotateRight(Node* node)
	{
		//      node
		//   lc
		//      lrc
		Node* parent = node->_parent, * lc = node->_left, * lrc = node->_left->_right;
		node->_left = lrc;
		if (lrc) lrc->_parent = node;
		lc->_right = node;
		node->_parent = lc;
		if (parent == nullptr)
		{
			lc->_parent = nullptr;
			_root = lc;
		}
		else
		{
			if (parent->_left == node)
			{
				parent->_left = lc;
				lc->_parent = parent;
			}
			else
			{
				parent->_right = lc;
				lc->_parent = parent;
			}
		}
	}

	void InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		InOrder(root->_left);
		//cout << root->_date << " ";
		cout << root->_date <<"##";

		InOrder(root->_right);
	}

	void PreOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		cout << root->_date << "##";
		PreOrder(root->_left);
		PreOrder(root->_right);
	}
	Node* getRoot()
	{
		return _root;
	}
	bool isRBTree()
	{
		return isRBTree(_root, 0);
	}


private:
	bool isRBTree(Node* node, int cb)
	{
		if (node == nullptr)
		{
			if (cb == countBlack()) return true;
			else
			{
				return false;
			}
		}
		if (node->col == RED && node->_parent->col == RED)
		{
			return false;
		}
		int i = 0;
		if (node->col == BLACK) i++;
		return isRBTree(node->_left, cb + i) && isRBTree(node->_right, cb + i);
	}
	int countBlack()
	{
		int count = 0;
		Node* tmp = _root;
		while (tmp)
		{
			if (tmp->col == BLACK)
			{
				count++;
			}
			tmp = tmp->_right;
		}
		return count;
	}
	Node* _root;

};
相关推荐
小O的算法实验室1 小时前
2025年COR SCI2区,双种群 NSGA-II 算法+卡车–无人机–调度车辆的多目标应急物资调度,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
第二只羽毛1 小时前
C++高性能内存池
开发语言·c++·缓存·性能优化
夏乌_Wx1 小时前
练题100天——DAY21
算法
ULTRA??1 小时前
动态内存管理:C语言malloc极简封装方案(修正版,可申请二维数组)
c语言·开发语言
梁正雄1 小时前
9、Python面向对象编程-1
服务器·开发语言·python
say_fall1 小时前
C++ 入门第一课:命名空间、IO 流、缺省参数与函数重载全解析
c语言·开发语言·c++
霸王大陆1 小时前
《零基础学 PHP:从入门到实战》模块十一:成为 PHP 侦探,精通错误处理与调试实战大全-1
开发语言·笔记·php·课程设计
赖small强1 小时前
【Linux C/C++开发】C++多态特性深度解析:从原理到实践
linux·c语言·c++·多态·虚函数表
郝学胜-神的一滴1 小时前
Python的内置类型:深入理解与使用指南
开发语言·python·程序人生