(三)红黑树

#ifndef _RB_TREE_
#define _RB_TREE_

#include <iostream>
#include <assert.h>

using namespace std;


void TestRBTree();

/*
	性质:
		1.每个节点要么是红色的,要么是黑色的
		2.根节点是黑色的
		3.每个叶节点是黑色的
		4.如果节点是红色的,则它的两个子节点都必须是黑色的
		5.对于每个节点,从该节点到其子孙节点的所有路径上包含相同数目的黑色节点

	实现RBTree的关键点:
		1.数据结构
		2.左、右旋转:对照着伪代码,好实现
		3.插入:对照着伪代码,好实现,但是理解起来,不太好理解,
		4.删除:知其然,知其所以然

*/

enum Color
{
	Red,
	Black
};

// 节点数据结构
struct RBTreeNode
{
	int key;
	Color color;
	RBTreeNode *left;
	RBTreeNode *right;
	RBTreeNode *parent; // 

	bool operator==(const RBTreeNode lhs)
	{
		return (key == lhs.key);
	}


};

/*
	旋转好实现,关键是识别出在哪里旋转,怎么旋转

	树的旋转:修改树中某些节点的颜色以及指针,使之符合定义
		左旋转:
			对某一个节点A实施左旋转:最大的右子结点B成为父节点,B的左子树成为
			A的右子树,A成为B的左子树
		右旋转:
			对某一个节点A实施右旋转:最大的左子节点B成为父节点,B的右子树成为
			A的左子树,A成为B的右子树
			
*/

/*
	节点插入:
		1.找到插入点
		2.插入节点,并设为RED
		3.调整树结构
	插入节点只会破坏2、4:因为插入默认的都是Red
	1.插入的是根节点
	2.插入的父节点是Black:OK
	3.当前节点的父节点是红色且叔叔节点也是红色:case1
		将当前节点的父节点和叔叔节点变为:black
		祖父节点变为:Red
		并将当前节点调整到祖父节点处
	4.当前节点的父亲节点是红色、叔叔节点时黑色、当前节点是右子树 :case2
		将当前节点的父节点作为当前节点,并左旋
	5.当前节点的父亲节点是红色、叔叔节点时黑色、当前节点是左子树 :case3
		当前节点的父节点变为:Black
		当前节点的祖父节点变为:Red
		对当前节点的祖父节点右旋

	case2先执行4到达case3,通过调整后满足要求
	case2->leftRotate->case3->rightRotate
*/

/*
	节点删除:
		如果删除的是Red,不用调整
		否则,需要调整

	1.当前节点是红色:
		直接染成黑色
	2.当前节点时黑色且是根节点
		结束
	3.当前节点时左子树,且当前节点为Black,兄弟节点是:Red
		父节点变为:Red
		兄弟节点变为:Black
		左旋:父亲节点
	4.当前节点为左子树,且当前节点为Black,兄弟节点:Black,且兄弟的两个孩子都是Black
		将兄弟节点变为:Red
		将当前节点置为父节点
	5.当前节点为左子树,且当前节点为Black,兄弟节点是Black,兄弟节点的右子树为Black,左子树为Red
		将兄弟节点的左子树置为Black
		兄弟节点置为Red
		右旋兄弟节点
	6.当前节点为左子树,且当前节点为Black,兄弟节点是Black,兄弟节点的右子树为Red,左子树任意
		将兄弟节点的颜色置为当前节点的父节点颜色
		将当前节点父节点的颜色置为:Black
		兄弟节点的右子树置为:Black
		左旋当前节点的父节点		
*/

// 左旋转
/*
	左旋转:
			对某一个节点A实施左旋转:最大的右子结点B成为父节点,B的左子树成为
			A的右子树,A成为B的左子树
*/	

// 对node节点进行左旋转
void LeftRotate(RBTreeNode * &root, RBTreeNode *node);

// 右旋转
/*
	右旋转:
			对某一个节点A实施右旋转:最大的左子节点B成为父节点,B的右子树成为
			A的左子树,A成为B的右子树
*/
void RightRotate(RBTreeNode * &root, RBTreeNode *node);

// 节点插入
void InsertNode(RBTreeNode * &root, RBTreeNode *node);

// 插入调整
void RBTreeInsertFixUp(RBTreeNode * &root, RBTreeNode *node);

// 删除节点
RBTreeNode* DeleteNode(RBTreeNode * &root, RBTreeNode *node);

// 得到一个节点的中序遍历的后继节点
RBTreeNode *Successor(RBTreeNode *node);

// 得到最小节点
RBTreeNode *Minimum(RBTreeNode *root);

void RBTreeDeleteFixUp(RBTreeNode * &root, RBTreeNode *node);











#endif

#include "3_RBTree.h"

void TestRBTree()
{
	cout << "Test RBTree" << endl;
}

// 对某一个节点A实施左旋转:最大的右子结点B成为父节点,B的左子树成为
// A的右子树,A成为B的左子树
void LeftRotate(RBTreeNode * &root, RBTreeNode *node)
{
	// 假定node的右子节点不为空
	assert(node->right);
	RBTreeNode *right = node->right;
	// right的左子树成为node的右子树
	node->right = right->left;
	right->left->parent = node;

	// 设置right的父节点
	right->parent = node->parent;

	// 如果原来right为root 
	if (right->parent == NULL)
	{
		root = right;		
	}
	else 
	{		
		if (node == node->parent->left)
		{
			node->parent->left = right;
		}
		else
		{
			node->parent->right = right;
		}
	}

	// 将right设置为node的左子节点
	node->parent = right;
	right->left = node;
}


// 对某一个节点A实施右旋转:最大的左子节点B成为父节点,B的右子树成为
// A的左子树,A成为B的右子树
void RightRotate(RBTreeNode * &root, RBTreeNode *a)
{
	RBTreeNode *b = a->left;
	assert(b);

	// 将b的右子树设为a的左子树
	a->left = b->right;
	b->right->parent = a;

	// 设置b的parent
	b->parent = a->parent;

	// a为root
	if (a->parent == NULL)
	{
		root = b;
	}
	else
	{
		if (a->parent->left == a)
		{
			a->parent->left = b;
		}
		else
		{
			a->parent->right = b;
		}
	}
	// a成为b的右子树
	b->right = a;
	a->parent = b;
}


/*
	节点插入:
		1.找到插入点
		2.插入节点,并设为RED
		3.调整树结构	
*/
void InsertNode(RBTreeNode * &root, RBTreeNode *node)
{
	// 找到插入点
	assert(node);
	RBTreeNode *x = root;
	RBTreeNode *y = NULL;
	while (x)
	{
		y = x;
		if (x->key < node->key)
		{
			x = x->left;
		}
		else
		{
			x = x->right;
		}
	}
	node->parent = y;
	// 如果y为空,说明root为空
	if (y == NULL)
	{
		root = node;
	}
	else if (y->key < node->key)
	{
		y->right = node;
	}
	else
	{
		y->left = node;
	}
	node->left = NULL;
	node->right = NULL;
	node->color = Color::Red;

	RBTreeInsertFixUp(root, node);
}

/*
	插入节点只会破坏2、4:因为插入默认的都是Red
	1.插入的是根节点
	2.插入的父节点是Black:OK
	3.当前节点的父节点是红色且叔叔节点也是红色:case1
		将当前节点的父节点和叔叔节点变为:black
		祖父节点变为:Red
		并将当前节点调整到祖父节点处
	4.当前节点的父亲节点是红色、叔叔节点时黑色、当前节点是右子树 :case2
		将当前节点的父节点作为当前节点,并左旋
	5.当前节点的父亲节点是红色、叔叔节点时黑色、当前节点是左子树 :case3
		当前节点的父节点变为:Black
		当前节点的祖父节点变为:Red
		对当前节点的祖父节点右旋

	case2先执行4到达case3,通过调整后满足要求
	case2->leftRotate->case3->rightRotate
*/
void RBTreeInsertFixUp(RBTreeNode * &root, RBTreeNode *node)
{
	while (node->parent->color == Color::Red)
	{
		// 左子节点
		if (node->parent == node->parent->parent->left)
		{
			// 叔叔节点
			RBTreeNode *y = node->parent->parent->right;
			if (y->color == Color::Red)	// case 1
			{
				node->parent->color = Color::Black;
				y->color = Color::Black;
				node->parent->parent->color = Color::Red;
				node = node->parent->parent;
			} // 如果node是右子结点
			else if (node == node->parent->right) // case 2
			{
				node = node->parent;
				LeftRotate(root, node);
			}

			node->parent->color = Color::Black;
			node->parent->parent->color = Color::Red;
			RightRotate(root, node->parent->parent);
		}
		// 右子节点
		else
		{
			// 叔叔节点
			RBTreeNode *y = node->parent->parent->left;
			if (y->color == Color::Red)	// case 1
			{
				node->parent->color = Color::Black;
				y->color = Color::Black;
				node->parent->parent->color = Color::Red;
				node = node->parent->parent;
			} // 如果node是右子结点
			else if (node == node->parent->left) // case 2
			{
				node = node->parent;
				RightRotate(root, node);
			}

			node->parent->color = Color::Black;
			node->parent->parent->color = Color::Red;
			LeftRotate(root, node->parent->parent);
		}
	}
	root->color = Color::Black;
}

RBTreeNode* DeleteNode(RBTreeNode * &root, RBTreeNode *node)
{
	// 172 12.3 155?
	RBTreeNode *y = NULL;
	if ((node->left == NULL) || (node->right == NULL))
	{
		y = node;
	}
	else
	{
		y = Successor(node);
	}
	RBTreeNode *x = NULL;
	if (y->left)
	{
		x = y->left;
	}
	else
	{
		x = y->right;
	}
	x->parent = y->parent;
	if (y->parent == NULL)
	{
		root = x;
	}
	else
	{
		if (y == y->parent->left)
		{
			y->parent->left = x;
		}
		else
		{
			y->parent->right = x;
		}
	}
	if (!(y == node))
	{
		node->key = y->key;
		node->color = y->color;
		node->left = y->left;
		node->right = y->right;
		node->parent = y->parent;
	}
	if (y->color == Color::Black)
	{
		RBTreeDeleteFixUp(root, x);
	}
	return y;
}

/*
	节点删除:
		如果删除的是Red,不用调整
		否则,需要调整

	1.当前节点是红色:
		直接染成黑色
	2.当前节点时黑色且是根节点
		结束
	3.当前节点时左子树,且当前节点为Black,兄弟节点是:Red
		父节点变为:Red
		兄弟节点变为:Black
		左旋:父亲节点
	4.当前节点为左子树,且当前节点为Black,兄弟节点:Black,且兄弟的两个孩子都是Black
		将兄弟节点变为:Red
		将当前节点置为父节点
	5.当前节点为左子树,且当前节点为Black,兄弟节点是Black,兄弟节点的右子树为Black,左子树为Red
		将兄弟节点的左子树置为Black
		兄弟节点置为Red
		右旋兄弟节点
	6.当前节点为左子树,且当前节点为Black,兄弟节点是Black,兄弟节点的右子树为Red,左子树任意
		将兄弟节点的颜色置为当前节点的父节点颜色
		将当前节点父节点的颜色置为:Black
		兄弟节点的右子树置为:Black
		左旋当前节点的父节点		
*/
void RBTreeDeleteFixUp(RBTreeNode * &root, RBTreeNode *x)
{
	while (x != root && x->color == Color::Black)
	{
		// x为左子节点
		if (x == x->parent->left)
		{
			// w为其兄弟节点
			RBTreeNode *w = x->parent->right;
			if (w->color == Color::Red)
			{
				x->parent->color = Color::Red;
				w->color = Color::Black;
				LeftRotate(root, x->parent);
			}
			if (w->left->color == Color::Black &&
				w->right->color == Color::Black)
			{
				w->color = Color::Red;
				x = x->parent;
			}
			else if (w->right->color == Color::Black)
			{
				w->left->color = Color::Black;
				w->color = Color::Red;
				RightRotate(root, w);
				w = x->parent->right;
			}
			w->color = x->parent->color;
			x->parent->color = Color::Black;
			w->right->color = Color::Black;
			LeftRotate(root, x->parent);
			x = root;				 
		}
		else
		{
			// w为其兄弟节点
			RBTreeNode *w = x->parent->left;
			if (w->color == Color::Red)
			{
				x->parent->color = Color::Red;
				w->color = Color::Black;
				RightRotate(root, x->parent);
			}
			if (w->right->color == Color::Black &&
				w->left->color == Color::Black)
			{
				w->color = Color::Red;
				x = x->parent;
			}
			else if (w->left->color == Color::Black)
			{
				w->right->color = Color::Black;
				w->color = Color::Red;
				LeftRotate(root, w);
				w = x->parent->left;
			}
			w->color = x->parent->color;
			x->parent->color = Color::Black;
			w->left->color = Color::Black;
			RightRotate(root, x->parent);
			x = root;
		}
	}
}

RBTreeNode *Successor(RBTreeNode *node)
{
	if (node->right)
	{
		return Minimum(node);
	}
	RBTreeNode *y = node->parent;
	// 找到第一个node不是其右子节点,而是其子节点的节点
	while (y && (node == y->right))
	{
		node = y;
		y = y->parent;
	}
	return y;
}

RBTreeNode *Minimum(RBTreeNode *root)
{
	while (root->left)
	{
		root = root->left;
	}
	return root;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值