【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;

};
相关推荐
jingli97 分钟前
本地向量库索引把 C 盘塞爆 48.6G:一次 LanceDB 膨胀排查与根治实录
c语言·开发语言
言乐68 分钟前
Python排名统计折线图
开发语言·python·django·virtualenv·pygame
u01110267514 分钟前
图片预览越来越占内存聊聊 URL.createObjectURL 的释放时机
图像处理·深度学习·算法·ai作画
Zane199415 分钟前
同样是遍历图,为什么BFS能保证找到最短路径,DFS却不行
算法
无限码力15 分钟前
2026华为OD机试真题 新系统 9月27日【坚果巧克力】
算法·华为od·华为od机考·华为od机试真题·华为od机试·华为od机考真题题解·华为社招笔试真题
samforce19 分钟前
叹息之墙——人类认知 AI,终将遇到的一堵同构之墙
人工智能·深度学习·算法·哲学·认知科学
艾莉丝努力练剑25 分钟前
【AI大模型接入SDK】ChatSDK整体实现
网络·c++·人工智能·学习·架构
我是小白呀25 分钟前
19-Temporal项目实战:将客户开通流程迁移到持久执行架构
java·开发语言·人工智能·架构·workflow
励志不掉头发的内向程序员27 分钟前
【从零写一个CAD 02】画完第一条线之后:实体容器、Esc 取消,和按了没反应的键盘
开发语言·c++·qt·学习·系统架构
l1t30 分钟前
编译测试兼容gzip并行压缩解压工具pigz
c++·算法