红黑树

本文深入探讨了红黑树的插入操作,详细分析了不同情况下红黑树如何保持其平衡特性,特别是对于新插入节点为红色时的具体处理方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

彻底搞懂红黑树(二)

原创  2012年10月16日 16:31:20

其实关于红黑树,STL源码剖析---红黑树原理详解 已经写得非常好了。但套用新警察故事里的谢霆锋说的一句话:自己查,印象深一点。这里也是一样,在自己写,印象深一点。如果你要看正宗的STL源码剖析---红黑树原理详解,那请你点击这个。这里的是D版的o(╯□╰)o  当然,我也会加一些我自己的理解,因为大神写文章都比较精简,而我这是写给我自己看的,有一点口水话加深点印象。

三 红黑树的插入


红黑树的节点插入默认是节点为红色的。我自己理解是,其实插入红还是黑都可以,但就要看后面的调整是否麻烦。

插入黑点,会增加路径上黑点的数目,一定会破坏性质5
插入红点:

当其父节点为黑色时,不影响平衡,继续保持红黑性质
当其父节点为红色时,可能破坏性质2(根节点是黑色的)、性质4(红色节点的子节点一定是黑色节点),需要进行修正。

因为第一篇文章已经说了,黑节点至少是红节点的两倍,这说明插入红节点OK的概率高很多(因为父节点为黑,插入子节点为红色就不会和性质冲突),这样插入就省事多了,嘿嘿,这也是红黑树为什么战胜AVL树的原因之一,插入效率高啊,节点贴上去就ok了,都不用什么左转右转调整了,多省事啊;再说,如果插入子节点为黑色,o(╯□╰)o了,黑高度变化了,得调整,如果每次都插入黑节点,都得调整,没事闲的蛋疼啊。。。


红黑树插入分一下几种情况:

1、黑父

   如下图所示,如果新节点的父结点为黑色结点,那么插入一个红点将不会影响红黑树的平衡,此时插入操作完成。红黑树比AVL树优秀的地方之一在于黑父的情况比较常见,从而使红黑树需要旋转的几率相对AVL树来说会少一些。(大神和我的理解差不多,不过别人的精简很多,我的就是口水话。)

2、红父
     如果新节点的父结点为红色,这时就需要进行一系列操作以保证整棵树红黑性质。如下图所示,由于父结点为红色,此时可以判定,祖父结点必定为黑色。这时需要根据叔父结点的颜色来决定做什么样的操作。青色结点表示颜色未知。由于有可能需要根结点到新点的路径上进行多次旋转操作,而每次进行不平衡判断的起始点(我们可将其视为新点)都不一样。所以我们在此使用一个蓝色箭头指向这个起始点,并称之为判定点。
图一
2.1 红叔
当叔父结点为红色时,如下图所示,无需进行旋转操作,只要将父和叔结点变为黑色,将祖父结点变为红色即可。但由于祖父结点的父结点有可能为红色,从而违反红黑树性质。此时必须将祖父结点作为新的判定点继续向上(迭代)进行平衡操作。(注意这里是需要迭代的,有可能会调整到根节点)

图二
需要注意的是,无论“父节点”在“叔节点”的左边还是右边,无论“新节点”是“父节点”的左孩子还是右孩子,它们的操作都是完全一样的(其实这种情况包括4种,只需调整颜色,不需要旋转树形)。


2.2 黑叔
当叔父结点为黑色时,需要进行旋转,以下图示了所有的旋转可能:(case1 和caes 2 都是把左边较大的节点调整到上面去

Case 1:


图三

Case 2:


图四

其实这里case 2的图示进行了简化,就是case 2 需要L变换成case 1 的情形如然后再进行R旋转,得到最后的结果。 当然,下面的也一样



图五(图中省略了哨兵结点



Case 3:

Case 4:


      可以观察到,当旋转完成后,新的旋转根全部为黑色,此时不需要再向上回溯进行平衡操作,插入操作完成。需要注意,上面四张图的“叔”、“1”、“2”、“3”结点有可能为黑哨兵结点。

      有了上面的分析,红黑树的插入就好理解多了,代码也容易读懂。不过不是很喜欢c++的代码,有时间了把linux内核的红黑树源码贴出来。这里还是贴的大神注视的红黑树的插入操作源代码:

自己写的红黑树代码参考其他书籍中的描述(代码有错有时间更改大题思路如下)

#ifndef _REDBLACKTREE_
#define _REDBLACKTREE_
static const int red = 0;
static const int black = 1;
template <typename T>
class RedBlackTree;
template <typename T>
class RedBlackNode
{
public:
	RedBlackNode(const T &element = T(), RedBlackNode *lt = NULL, RedBlackNode*rt = NULL,int mcolor = red) :ement(element), left(lt), right(rt), color(mcolor){}

private:
	RedBlackNode<T> *left;
	RedBlackNode<T> *right;
	T ement;
	int color;
	friend class RedBlackTree<T>;


};
template <typename T>
class RedBlackTree
{
public:
	typedef RedBlackNode<T> Node;
	RedBlackTree(const T &neglnf = T());
	~RedBlackTree();
	void insert(const T &data);
	void RotateWitthRightChild_s(Node * &k2);
	void RotateWitthRightChild();
	void RotateWitthLeftChild_s(Node * &k2);
	void RotateWitthLeftChild();
	void doubleRotateWitthRightChild_s(Node  *&k2);
	void doubleRotateWitthRightChild();
	void doubleRotateWitthLeftChild_s(Node  *&k2);
	void doubleRotateWitthLeftChild();
	void HandleReorient(const T &item);
	RedBlackNode<T> *rotate(const T&item, Node *parent);
	void PerOrder();
	void PerOrder_s( Node* node);
	T& Root();
private:
	Node *head;//指向红黑树的头
	Node *nullnode;//空节点	
	Node *current;//指向当前节点
	Node *parent;//父节点
	Node *grand;//祖父节点;
	Node *great;//曾祖父节点
};
template<typename T>
RedBlackTree<T>::RedBlackTree(const T &neglnf = T())
{
	nullnode = new Node();
	nullnode->left = nullnode->right = nullnode;
	head = new Node(neglnf);
	head->left = head->right = nullnode;

}
template<typename T>
void RedBlackTree<T>::PerOrder_s(Node* node)
{
	if (node == nullnode)
	{
		return;
	}
	PerOrder_s(node->left);
	cout << node->ement << endl;
	PerOrder_s(node->right);

}
template<typename T>
void RedBlackTree<T>::PerOrder()
{
	PerOrder_s(head->right);
}
template<typename T>
T& RedBlackTree<T>::Root()
{
	return head->right->ement;
}
template<typename T>
RedBlackTree<T>::~RedBlackTree()
{
	delete head;
	delete nullnode;
}
template<typename T>
void RedBlackTree<T>::insert(const T &data)
{
	current = parent = grand = head;
	nullnode->ement = data;
	while (current->ement != data)
	{
		great = grand;
		grand = parent;
		parent = current;
		current = (data < current->ement) ? current->left : current->right;
		if (current->left->color == red&¤t->right->color == red)
		{
			HandleReorient(data);
		}
	}
	if (current != nullnode)
	{
		throw "erro";
	}
	current = new Node(data, nullnode, nullnode);
	if (data < parent->ement)
	{
		parent->left = current;
	}
	else
	{
		parent->right = current;
	}//自动平衡-》旋转左转和 右转进行红黑树旋转
	HandleReorient(data);//插入的时候后进行调整;
}
template<typename T>
void RedBlackTree<T>::RotateWitthRightChild_s(Node *&node)
{
	Node* mleft = node->left;
	node->left = mleft->right;
	mleft->right = node;
	node = mleft;//用该地址覆盖掉原来的node根
	
}
template<typename T>
void RedBlackTree<T>::RotateWitthRightChild()
{
	RotateWitthRightChild_s(head->right);

}
template<typename T>
void RedBlackTree<T>::RotateWitthLeftChild()
{
	RotateWitthLeftChild_s(head->right);

}
template<typename T>
void RedBlackTree<T>::RotateWitthLeftChild_s(Node *&node)
{
	Node* mright = node->right;
	node->right = mright->left;
	mright->left = node;
	node = mright;
}
template<typename T>
void RedBlackTree<T>::doubleRotateWitthRightChild_s(Node *&node)//
{
//两次单转 第一次向右第二次向左	
	RotateWitthRightChild_s(node->left);//先左转
	RotateWitthLeftChild_s(node);//在右转
}
template<typename T>
void RedBlackTree<T>::doubleRotateWitthRightChild()//带着做孩子啊向右转
{
	doubleRotateWitthRightChild_s(head->right->left);
}
template<typename T>
void RedBlackTree<T>::doubleRotateWitthLeftChild_s(Node *&node)
{
	RotateWitthRightChild_s(node);
	RotateWitthLeftChild_s(node->left);//先右转在左转
	

}
template<typename T>
void RedBlackTree<T>::doubleRotateWitthLeftChild()
{
	doubleRotateWitthLeftChild_s(head->right->left);
}
template<typename T>

void RedBlackTree<T>::HandleReorient(const T & item)
{
	
	current->color = red;
	current->left->color = current->right->color = red;
	if (parent->color == red)
	{
		grand->color = red;
		if (item < grand->ement != item < parent->ement)//判断是不是内部孙子
		{
			parent = rotate(item, grand);
		}
		else
		{
			current = rotate(item,great);
		}
		current->color = black;

	}
	head->right->color = black;
}
template <typename T>
RedBlackNode<T>* RedBlackTree<T>::rotate(const T &item, Node *parent)
{
	if (item < parent->ement)
	{
		if (item < parent->left->ement)
			RotateWitthLeftChild_s(parent->left);
		RotateWitthRightChild_s(parent->left);
		return parent->left;
	}
	else
	{
		if (item < parent->right->ement)
		{
			RotateWitthLeftChild_s(parent->right);
		}
		else
		{
			RotateWitthRightChild_s(parent->right);
		}
		return parent->right;
	}

}
#endif 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值