红黑树 | C++实现

1.红黑树的定义与性质

红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过 对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩 倍,因而是接近平衡的。
性质:

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

2.节点定义

struct RBTNode
{
	RBTNode(const pair<K,V>& data = pair<K,V>())
		:_parent(nullptr)
		,_right(nullptr)
		,_left(nullptr)
		,color(red)
		,_data(data)
	{}
	pair<K,V> _data;
	RBTNode<K,V>* _parent;
	RBTNode<K,V>* _right;
	RBTNode<K,V>* _left;
	COLOR color;
};

3.如何调整?

3.1 情况一:父节点为红,叔叔节点为红

来看下面这种情况:
插入cur节点时,左侧出现两个连续的红色节点,此时就需要调整,我们发现叔叔节点u存在,所以处理方式是,将父节点与叔叔节点同时变黑,并将祖父节点g变为红色。然后cur交换至g,继续向上调整。
在这里插入图片描述

3.2 情况2:父节点为红,叔叔节点为黑/不存在

此时分为两种情况:
情况a: 父节点为祖父节点的左(右)节点,插入节点cur为父节点的左(右)节点。
来看这种情况:
插入节点为父节点的左孩子,处理方法为:对p进行右旋转,随后将g变为红,p变为黑。
在这里插入图片描述

**情况b:**父节点为祖父节点的左(右)节点,插入节点cur为父节点的右(左)节点。
来看这种情况:
插入节点为父亲的左孩子,处理方法为:
先对父节点p进行做单旋,得到如下结果,此时就变为了情况a,然后使用情况a的方法,即可完成调整。

在这里插入图片描述

bool Insert(const pair<K, V>& data)
	{
		if (_head->_parent == nullptr)
		{
			Node* root = new Node(data);
			_head->_parent = root;
			_head->_left = _head->_right = root;
			root->color = black;
			root->_parent = _head;
			return true;
		}
		Node* cur = _head->_parent;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->_data.first == data.first)
			{
				return false;
			}
			if (cur->_data.first > data.first)
				cur = cur->_left;
			else
				cur = cur->_right;
		}
		cur = new Node(data);
		if (parent->_data.first > data.first)
			parent->_left = cur;
		else
			parent->_right = cur;
		cur->_parent = parent;

		//调整 : cur和parent都为红色,需要调整
		while (cur != _head->_parent && cur->_parent->color == red)
		{
			Node* parent = cur->_parent;
			Node* Gparent = parent->_parent;
			//祖父节点的左孩子存在并且为红色
			if (Gparent->_left == parent)
			{
				Node* uncle = Gparent->_right;
				if (uncle && uncle->color == red)
				{
					uncle->color = parent->color = black;
					Gparent->color = red;
					cur = Gparent;
				}
			         //如果cur = parent->right 左单旋一次  
					 //cur = parent->left 右单旋一次 得到上面的情况 再做单旋一次即可
			    else
				{
					if (cur == parent->_right)
					{
						RotateLeft(parent);
						swap(cur, parent);
					}
					RotateRight(Gparent);
					parent->color = black;
					Gparent->color = red;
					break;
				}
			}
			else
			{
				Node *uncle = Gparent->_left;
				if (uncle && uncle->color == red)
				{
					uncle->color = parent->color = black;
					Gparent->color = red;
					cur = Gparent;
				}
				else
				{
					if (cur == parent->_left)
					{
       					RotateRight(parent);
						swap(cur, parent);
					}
					RotateLeft(Gparent);
					parent->color = black;
					Gparent->color = red;
					break;
				}
			}
		}
		_head->_parent->color = black;
		_head->_right = rightMost();
		_head->_left = leftMost();
		return true;
	}

4.如何验证?

  • 先验证是否满足搜索二叉树。
  • 再验证是否满足红黑树的性质。
//判断是否是红黑树的条件:
	//不能连续两个红色
	//一个路径上黑色必须相同
	//root 必须为黑色
	bool IsRBTree()
	{
		Node* root = _head->_parent;
		if (root == nullptr)
			return true;
		if (root->color == red)
			return false;
		Node* cur = root;
		int BlackCout = 0;
		while (cur)
		{
			if (cur->color == black)
				BlackCout++;
			cur = cur->_left;           //找到一个基准值 然后遍历(前序)所有路径 如果都一样 则返回true
		}
		_IsRBTree(root, BlackCout, 0);
	}
	bool _IsRBTree(Node* root, int BlackCout, int NowCout)
	{
		if (root == nullptr)
		{
			if (BlackCout == NowCout)
				return true;
			return false;
		}
		if (root->color == black)
			NowCout++;
		if (root->color == red && root->_parent->color == red)
			return false;
		return _IsRBTree(root->_left, BlackCout, NowCout) && _IsRBTree(root->_right, BlackCout, NowCout);
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个用 C 实现红黑树: ```c #include <stdio.h> #include <stdlib.h> typedef enum Color { RED, BLACK } Color; typedef struct Node { int value; Color color; struct Node *left; struct Node *right; struct Node *parent; } Node; Node *root = NULL; Node *createNode(int value, Color color) { Node *newNode = (Node *) malloc(sizeof(Node)); newNode->value = value; newNode->color = color; newNode->left = NULL; newNode->right = NULL; newNode->parent = NULL; return newNode; } Node *findSibling(Node *node) { Node *parent = node->parent; if (parent == NULL) { return NULL; } if (parent->left == node) { return parent->right; } else { return parent->left; } } Color getNodeColor(Node *node) { if (node == NULL) { return BLACK; } else { return node->color; } } Node *leftRotate(Node *node) { Node *pivot = node->right; node->right = pivot->left; if (pivot->left != NULL) { pivot->left->parent = node; } pivot->parent = node->parent; if (node->parent == NULL) { root = pivot; } else if (node == node->parent->left) { node->parent->left = pivot; } else { node->parent->right = pivot; } pivot->left = node; node->parent = pivot; return pivot; } Node *rightRotate(Node *node) { Node *pivot = node->left; node->left = pivot->right; if (pivot->right != NULL) { pivot->right->parent = node; } pivot->parent = node->parent; if (node->parent == NULL) { root = pivot; } else if (node == node->parent->left) { node->parent->left = pivot; } else { node->parent->right = pivot; } pivot->right = node; node->parent = pivot; return pivot; } void fixInsert(Node *node) { while (node->parent != NULL && node->parent->color == RED) { Node *parent = node->parent; Node *grandparent = parent->parent; Node *uncle = findSibling(parent); if (getNodeColor(uncle) == RED) { parent->color = BLACK; uncle->color = BLACK; grandparent->color = RED; node = grandparent; } else { if (parent == grandparent->left) { if (node == parent->right) { node = leftRotate(parent); parent = node->parent; } rightRotate(grandparent); } else { if (node == parent->left) { node = rightRotate(parent); parent = node->parent; } leftRotate(grandparent); } parent->color = BLACK; grandparent->color = RED; } } root->color = BLACK; } void insertNode(int value) { Node *newNode = createNode(value, RED); if (root == NULL) { root = newNode; } else { Node *current = root; Node *parent = NULL; while (current != NULL) { parent = current; if (value < current->value) { current = current->left; } else { current = current->right; } } newNode->parent = parent; if (value < parent->value) { parent->left = newNode; } else { parent->right = newNode; } fixInsert(newNode); } } void printTree(Node *node, int space) { if (node == NULL) { return; } space += 10; printTree(node->right, space); printf("\n"); for (int i = 10; i < space; i++) { printf(" "); } printf("%d (%s)\n", node->value, node->color == RED ? "RED" : "BLACK"); printTree(node->left, space); } int main() { insertNode(10); insertNode(20); insertNode(30); insertNode(40); insertNode(50); insertNode(60); insertNode(70); printTree(root, 0); return 0; } ``` 这个简单的红黑树实现包含了插入节点和打印红黑树的功能。它基于二叉搜索树的规则插入节点,并通过旋转和重新着色来保持红黑树的平衡。在插入节点后,通过 fixInsert 函数来调整红黑树。打印红黑树的功能使用递归方式实现。你可以运行这个代码来检查红黑树的输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值