红黑树

基本思想

红黑树是一种特殊的二叉搜索树,它在二叉搜索树的基础上增加了着色和相关限制,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。

红黑树相较AVL是牺牲了严格的高度平衡的条件为代价,它只要求部分地达到平衡要求,降低了对旋转的要求,从而提高了性能。由于它的设计,任何不平衡都会在三次旋转之内解决。(插入需两次旋转,删除需三次)

具体来说,红黑树有以下几个限制条件:

  1. 每个节点要么是红色,要么是黑色。
  2. 根节点必须是黑色的。
  3. 红色节点的孩子必须是黑色的。
  4. 对于每个节点而言,其到树尾端NULL指针的每条路径都包含相同数目的黑节点。

由限制条件可得出对于某一节点,其左右子树的高度相差不会超过一倍,这也就保证了红黑树O(logn)的效率。

红黑色的查找、插入、删除操作跟二叉搜索树很相似,只不过由于限制条件,在插入、删除节点后,需要调整树以重新符合限制条件。

左旋、右旋

当红黑树的条件被破坏之后,需要调整树以重新满足限制条件。调整的操作分为两类:一是对于节点颜色的改变,二是对于树结构的调整。而调整树的两个基本操作就是左旋与右旋。
在这里插入图片描述

在这里插入图片描述

插入节点

步骤一:将红黑树当做普通二叉搜索树,插入节点
注意新插入的节点颜色为红色。

步骤二:通过旋转及着色等操作使其重新恢复红黑树条件

(1) 插入节点为根节点(即原来树为空)
直接将该节点涂为黑色即可

(2)插入节点的父节点为黑色节点
无需任何操作,此时仍符合条件

(3)插入节点的父节点为红色节点

①当前节点的父节点是红色,且当前节点的祖父节点的另一个子节点(叔叔节点)也是红色。
把父节点和叔叔节点涂为黑色,把祖父节点涂为红色,接着设祖父节点为“当前节点”,继续进行处理。

②当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的右孩子
将父节点设为“新的当前节点”,并以“新的当前节点”进行左旋。

③当前节点的父节点是红色,叔叔节点是黑色,且当前节点是其父节点的左孩子
将父节点涂为黑色,将祖父节点涂为红色,对祖父节点进行右旋。

具体来说就是,情况①把自身处理好了后,把黑锅“嫁祸”给祖父节点进行处理。而情况②就是把自身转为情况③再进行处理。处理起来就好像红色节点逐渐地被传递给了上层,最终需把根节点涂为黑色。

下图为一次调整流程。
在这里插入图片描述

删除节点

删除同样是跟普通二叉搜索树一样,只不过删除后要调整树以重新满足限制条件,这里我真的看不懂,写不出来,留个坑吧。

定义

enum Color{RED, BLACK};

template <typename T>
class Node
{
public:
	T key;
	Color color;
	Node* parent;
	Node* left;
	Node* right;
	
	Node(T k, Color c, Node* p = nullptr, Node* l = nullptr, Node* r = nullptr) :
		key(k), color(c), parent(p), left(l), right(r) {}
};

template <typename T>
class RBTree
{
private: 
	Node<T>* root_;
public:
	RBTree();
	~RBTree();

	Node<T>* Search(T key);
	void Insert(T key);
	void Remove(T key);
private:
	void LeftRotate(Node<T>* head);
	void RightRotate(Node<T>* head);

	void FixAfterInsert(Node<T>* node);
	void FixAfterRemove(Node<T>* node);
	void Destory(Node<T>* &head);
};

代码

template <typename T>
RBTree<T>::RBTree() : root_(nullptr) {}

template <typename T>
RBTree<T>::~RBTree()
{
	Destory(root_);
}

template <typename T>
Node<T>* RBTree<T>::Search(T key)
{
	Node<T>* cur = root_;
	while (cur && cur->key != key)
	{
		if (key < cur->key)
			cur = cur->left;
		else
			cur = cur->right;
	}
	return cur;
}

// 将head节点左旋
template <typename T>
void RBTree<T>::LeftRotate(Node<T>* head)
{
	Node<T>* tmp = head->right;

	head->right = tmp->left;
	if (tmp->left)
		tmp->left->parent = head;

	tmp->parent = head->parent;
	if (head->parent)
	{
		if (head->parent->left == head)
			head->parent->left = tmp;
		else
			head->parent->right = tmp;
	}
	else
	{
		root_ = tmp;
	}

	head->parent = tmp;
	tmp->left = head;
}

// 将head节点右旋
template <typename T>
void RBTree<T>::RightRotate(Node<T>* head)
{
	Node<T>* tmp = head->left;

	head->left = tmp->right;
	if (tmp->right)
		tmp->right->parent = head;

	tmp->parent = head->parent;
	if (head->parent)
	{
		if (head->parent->left == head)
			head->parent->left = tmp;
		else
			head->parent->right = tmp;
	}
	else
	{
		root_ = tmp;
	}

	head->parent = tmp;
	tmp->right = head;
}

template <typename T>
void RBTree<T>::FixAfterInsert(Node<T>* node)
{
	Node<T>* parent;
	Node<T>* gparent;

	// 父节点存在,且为红色
	while ((parent = node->parent) && parent->color == RED)
	{
		gparent = parent->parent;
		
		// 父节点为祖父节点的左孩子
		if (parent == gparent->left)
		{
			// 情况1:叔叔节点也为红色
			Node<T>* uncle = gparent->right;
			if (uncle && uncle->color == RED)
			{
				parent->color = BLACK;
				uncle->color = BLACK;
				gparent->color = RED;
				node = gparent; // 往上层继续处理
				continue;
			}

			// 情况2:叔叔节点为黑色,且当前节点是右孩子
			if (parent->right == node)
			{
				LeftRotate(parent);
				Node<T>* tmp = parent;
				parent = node;
				node = tmp;
			}

			// 情况3:叔叔节点为黑色,且当前节点为左孩子
			parent->color = BLACK;
			gparent->color = RED;
			RightRotate(gparent);
		}
		else
		{
			Node<T>* uncle = gparent->left;
			if (uncle && uncle->color == RED)
			{
				parent->color = BLACK;
				uncle->color = BLACK;
				gparent->color = RED;
				node = gparent; 
				continue;
			}

			if (parent->left == node)
			{
				RightRotate(parent);
				Node<T>* tmp = parent;
				parent = node;
				node = tmp;
			}

			parent->color = BLACK;
			gparent->color = RED;
			LeftRotate(gparent);
		}
	}

	
	root_->color = BLACK;
}

template <typename T>
void RBTree<T>::Insert(T key)
{
	Node<T>* cur = root_;
	Node<T>* pre = nullptr;

	// 找到插入位置
	while (cur)
	{
		pre = cur;
		if (key == cur->key)
			return;
		else if (key < cur->key)
			cur = cur->left;
		else
			cur = cur->right;
	}

	Node<T>* new_node = new Node<T>(key, RED);
	new_node->parent = pre;
	// 插入为根节点
	if (pre == nullptr)
		root_ = new_node;
	// 插入为左孩子
	else if (key < pre->key)
		pre->left = new_node;
	// 插入为右孩子
	else
		pre->right = new_node;

	FixAfterInsert(new_node);
}

template <typename T>
void RBTree<T>::FixAfterRemove(Node<T>* node)
{
	Node<T>* brother;
	Node<T>* parent = node->parent;

	while ((!node || node->color == BLACK) && node != root_)
	{
		if (parent->left == node)
		{
			// case1
			brother = parent->right;
			if (brother->color == RED)
			{
				brother->color = BLACK;
				parent->color = RED;
				LeftRotate(parent);
				brother = parent->right;
			}

			// case2
			if ((!brother->left || brother->left->color == BLACK) &&
				(!brother->right || brother->right->color == BLACK))
			{
				brother->color = RED;
				node = parent;
				parent = node->parent;
			}
			else
			{
				// case3
				if (!brother->right || brother->right->color == BLACK)
				{
					brother->left->color = BLACK;
					brother->color = RED;
					RightRotate(brother);
					brother = parent->right;
				}
				// case 4
				brother->color = parent->color;
				parent->color = BLACK;
				brother->right->color = BLACK;
				LeftRotate(parent);
				node = root_;
				break;
			}
		}
		else
		{
			// case1
			brother = parent->left;
			if (brother->color == RED)
			{
				brother->color = BLACK;
				parent->color = RED;
				RightRotate(parent);
				brother = parent->left;
			}

			// case2
			if ((!brother->left || brother->left->color == BLACK) &&
				(!brother->right || brother->right->color == BLACK))
			{
				brother->color = RED;
				node = parent;
				parent = node->parent;
			}
			else
			{
				// case3
				if (!brother->left || brother->left->color == BLACK)
				{
					brother->right->color = BLACK;
					brother->color = RED;
					LeftRotate(brother);
					brother = parent->left;
				}
				// case 4
				brother->color = parent->color;
				parent->color = BLACK;
				brother->left->color = BLACK;
				RightRotate(parent);
				node = root_;
				break;
			}
		}
	}
	if (node)
		node->color = BLACK;
}

template <typename T>
void RBTree<T>::Remove(T key)
{
	Node<T>* r = Search(key);
	if (r == nullptr)
		return;

	// 左右孩子皆非空,转为至少有一空情况
	if (r->left != nullptr && r->right != nullptr)
	{
		Node<T>* cur = r->right;
		while (cur->left)
			cur = cur->left;

		r->key = cur->key;
		r = cur;
	}

	Node<T>* child = r->left != nullptr ? r->left : r->right;
	Node<T>* parent = r->parent;
	if (child) // 左右子树有一为空
	{
		child->parent = parent;
		if (parent == nullptr)
			root_ = child;
		else if (parent->left == r)
			parent->left = child;
		else
			parent->right = child;
		if (r->color == BLACK)
			FixAfterRemove(child);
	}
	else if (parent == nullptr) // 左右子树皆空,且该点为根节点
	{
		root_ = nullptr;
	}
	else // 左右子树皆空
	{
		if (r->color == BLACK)
			FixAfterRemove(r);
		if (r->parent != nullptr)
		{
			if (parent->left == r)
				parent->left = nullptr;
			else
				parent->right = nullptr;
		}
	}

	delete r;
}

template <typename T>
void RBTree<T>::Destory(Node<T>* &head)	
{
	if (head == nullptr)
		return;
	if (head->left)
		Destroy(head->left);
	if (head->right)
		Destroy(head->right);

	delete head;
	head = nullptr;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值