红黑树 插入

红黑树是一种二叉搜索树,每个节点增加一位来储存节点的颜色,红或黑。

红黑树通过如何一条从跟到叶子的路径上各个节点的着色方式的限制,红黑树确保没有一条路径比另一条路径长两倍。

其他性质:

根节点是黑色。

红色节点的子节点都为黑色。

叶子节点或NULL空节点都为黑色。所有原来的叶子节点都有NULL的空节点作为新的叶子节点,取代了自己的叶子节点的身份,即,所有的NULL节点都是黑色的意思。

最重要一点:任何一节点到叶子节点的NULL指针的路径经过的黑色节点数相同。

插入:

左旋 以节点p为支点的话,即p的右孩子为r,将p的右孩子赋值为r的左孩子,然后将r的左孩子赋值为p,最后将 p = r。

右旋 相反, p->left =  r -> right , r->right = p 。最后 p = r 。

这里使用递归的方法插入的话,p 每次都为其父节点的 孩子指针。但查了一下,一般实现红黑树都是直接使用父指针指向,即在节点中添加一个父指针。这样以空间换空间,递归费时费空间。

插入的情况:

1.插入节点即为根节点。将其标为黑色,结束。

2.如果父节点为黑色,则结束。

如果父节点为红色:父节点为红色必定有祖父,因为根节点是黑色。。。

3.叔叔节点为红色 : 将叔叔节点和父节点改为黑色,祖父改为红色,然后以祖父节点继续判断。

4.当叔叔节点是黑色时, 若当前节点p与其父节点f与其祖父节点g不在一条直线上时,即

当f为g的左孩子时,p为f的右孩子,这时要 以f为支点左旋,

当发为g的右孩子时,p为f的左孩子,这是要以f为支点右旋。

然后以f节点做为当前节点继续判断。

5.当叔叔节点是黑色时, 若当前节点与f和g和叔叔节点在一条直线时,则以祖父节点为做为支点旋转。

当f为g的左孩子,且p为f的左孩子,则以g为支点右旋转。

当f为g的右孩子,且p为f的右孩子,则以g为支点左旋。

然后将g节点设为红色,f节点设为黑色。结束。

这种情况就不会有进一步的可能了,因为除了当前节点,其他都是正确的。父节点是红色,则父节点的右孩子必是黑色的,将右孩子连接给祖父节点后,祖父节点是红色的,不会有异常,而父节点替代了祖父节点的位置,但父节点为黑色,所以也不会有异常。

这里右旋函数要考虑祖父节点就为根节点的情况,无法再寻找到其父节点。

这里可以发现,红黑树通过红黑两种颜色的设置,方便了树的旋转,使树处于平衡,至于这样做为何能确保平衡,我就无法深入研究了。

这里查了一些资料,被某篇博客坑了一下,然后自己也试着画些过程图帮助自己理解,画比较难看:

测试时,画出了从1插入到8的情况,验证代码正确。

试着写出代码

//改变其向下的指针的同时要更新其父指针。
template <typename T>
void RBTree<T>::LRotation(RBNode<T>* p){
	RBNode<T> *r = p->right;
	if(p->parent){
		if(p->parent->right == p) p->parent->right = r;
		else p->parent->left = r;
		r->parent = p->parent;
	}else{
		root = r;
		r->parent = 0;
	}
	p->parent = r;
	if(r->left)r->left->parent = p;
	p->right = r->left;
	r->left = p;
	return ;
}

template <typename T>
void RBTree<T>::RRotation(RBNode<T>* p){
	RBNode<T> *r = p->left;
	if(p->parent){
		if(p->parent->right == p) p->parent->right = r;
		else p->parent->left = r;
		r->parent = p->parent;
	}else{
		root = r;
		r->parent =0;
	}
	p->parent = r;
	if(r->right)r->right->parent = p;
	p->left = r->right;
	r->right = p;
	return ;
}

template <typename T>
bool RBTree<T>::Insert(const T &x){
	if(!root){
		root = new RBNode<T>(x,0);
		root->red = false;
		return true;
	}
	RBNode<T>* p = root, *fa=root;
	while(p){
		fa = p;
		if(x <p->value)
			p = p->left;
		else if(x > p->value)
			p = p->right;
		else
			return false;
	}
	if(x < fa->value)	p = fa->left = new RBNode<T>(x,fa);
	else  p = fa-> right = new RBNode<T>(x,fa);
	AdjustColor(p);
	return true;
}
template <typename T>
bool RBTree<T>::AdjustColor(RBNode<T> *p){
	if( p == root){
		p->red = false;
		return true;
	}
	else if( ! p->parent->red )
		return true;
	else {
		RBNode<T>* uncle, *f, *g;
		f = p -> parent;
		g = f->parent;
		bool uncleColor;//由于叔叔节点可能为空
		if(f == g->left)
			uncle = g->right;
		else
			uncle = g->left;
		if(uncle)uncleColor = uncle->red;
		else uncleColor = false;
		if(uncleColor){
			uncle->red = false;
			f->red = false;
			g->red = true;
			//将祖父节点设为红色
			AdjustColor(g);
		}else{
			if(g->left == f){
				if(f->left == p){
					g->red = true;
					f->red = false;
					RRotation(g);
				}else{
					LRotation(f);
					AdjustColor(f);
				}
			}else{
				if(f->right == p){
					g->red = true;
					f->red = false;
					LRotation(g);
				}else{
					RRotation(f);
					AdjustColor(f);
				}
			}
		}

	}
	return true;
}

这里有一点需要注意的是节点有父指针,旋转时要进行更新。

红黑树的删除!

红黑树的全部代码!

时间: 2024-10-06 14:58:50

红黑树 插入的相关文章

红黑树-插入操作

红黑树的五个性质: 1)每个结点要么是红的,要么是黑的. 2)根结点是黑的. 3)每个叶结点,即空结点(NIL)是黑的. 4)如果一个结点是红的,那么它的俩个儿子都是黑的. 5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点. 红黑树插入的几种情况: 1.树是空的,直接将节点设置为根节点,颜色为黑: public void case1(RBnode T,RBnode newNode){        if(newNode.getParent()==null){         

红黑树插入详解

查找二叉树插入节点: 已知查找二叉树的性质为根节点的值大于左子树的值,小于右子树的值,按照此规律,根据要插入的值为其寻找合适的插入位置,最后将其插入即可: Tree-Insert(T,z) { x = root(T); y = NULL; while(x != NULL) { y = x; if(key[z] < key[x]) x = left[x]; else x = right[x]; } p[z] = y; if(y == NULL) root[T] = z; else if(key[z

红黑树插入删除节点过程分析 &amp;&amp; C代码实现

红黑树的插入和删除规则: 红黑树的五个性质 1.    每个节点要么是红的,要么是黑的 2.    根节点时黑色的 3.    每个叶节点(叶节点既指树尾端NIL指针或NULL节点)是黑色的 4.    如果一个节点时红的,那么它的两个儿子都是黑色的 5.    对每个节点,其到叶节点树尾端NIL指针的每一条路径都包含相同数目的黑节点 这里所说的"叶节点"或者"NULL节点",它不包含数据而只充当树在此结束的知识. 二叉树的左旋和右旋这里不再讲解 红黑树的插入操作:

jdk源码分析红黑树——插入篇

红黑树是自平衡的排序树,自平衡的优点是减少遍历的节点,所以效率会高.如果是非平衡的二叉树,当顺序或逆序插入的时候,查找动作很可能会遍历n个节点 红黑树的规则很容易理解,但是维护这个规则难. 一.规则 1.每个节点要么是红色.要么是黑色 2.根节点一定是黑色 3.红色节点不可以连续出现(父节点.子节点不可同时为红) 4.从任意节点出发,到树底的所有路线,途径的黑节点数量必须相同 在修改红黑树的时候,切记要维护这个规则.一般默认插入红色节点(除非是root节点),插入后再进行旋转和颜色变换 二.旋转

初探红黑树-插入操作原理

事实总是因为人的欲望产生的, 想要才会有,而当大多数人想的一样的时候 就只会变成后人所得到生活 往复 引: 红黑树,应运而生 啊(叹气),反正我是这么认为的 比原来的它略显成熟,但又涉世不深,却又显其独到的风采 述: 需求,是红黑树的生来原因,哪方面呢,姑且我认为是效率 规则引来查询二叉树,简简单单,不复杂,说一就是一,说再见就再也不会见 但人的关系总是很复杂,规则也是相对的.当然也渲染到了查询二叉树身上 红黑树也只是复杂的其中一种而已,满足人们的欲求不满,可以这么说么? 路口一 基本理解树 基

红黑树插入和删除的情况分析

红黑树是特殊二叉查找树的一种,一颗红黑树有以下5种性质: 1.根节点为黑色. 2.每个节点不是黑色就是红色. 3.每个红色节点的两个儿子一定是黑色. 4.所有的叶子节点都是黑色.(注:这里的叶子节点并不是真正意义上的叶子节点,而是一种只有颜色属性但不存放数据的节点,而且其没有儿子节点) 5.一个红黑树的中任取一个节点,从它所在位置到其他任何叶子节点的简单路径上所经过的黑色节点数相同. 这2个性质决定了从根节点到叶子节点的最长路径不可能大于最短路径的2倍.所以红黑树是一个大致平衡的二叉树.但跟AV

算法导论 之 红黑树 - 插入[C语言]

作者:邹祁峰 邮箱:[email protected] 博客:http://blog.csdn.net/qifengzou 日期:2013.12.24 21:00 转载请注明来自"祁峰"的CSDN博客 1 引言 在之前的博文中,本人对平衡二叉树的处理做了较详尽的分析,有兴趣的朋友可以参阅博文<算法导论 之 平衡二叉树 - 创建 插入 搜索 销毁>和<算法导论 之 平衡二叉树 - 删除>.平衡二叉树AVL是严格的平衡树,在增删结点时,其旋转操作的次数较多:而红黑树

红黑树插入与删除完整代码(dart语言实现)

之前分析了红黑树的删除,这里附上红黑树的完整版代码,包括查找.插入.删除等.删除后修复实现了两种算法,均比之前的更为简洁.一种是我自己的实现,代码非常简洁,行数更少:一种是Linux.Java等源码版本的实现,实现的略为复杂,但效率更高.两种算法经过测试,在百万级的数据上效率不分伯仲:1000万的数据中,我自己的实现比Linux内核版本的运行时间多2秒左右. 红黑树的插入相对简单,本文中的代码实现与Linux源码版本也略有差异,效率差别不大. 其他方法,如查找.遍历等,比较简单,不多做解释.遍历

红黑树插入操作

通过具体分析每一步的操作来理解插入过程,将每一步操作之后的树结构打印出来可以帮助我们理解,在图中"#"表示黑色,"~"表示红色,空结点(NULL)都为黑色,但是没有被打印出来,看图像的时候注意一下就可以了. 下面将整个过程贴出来,所有的步骤都是通过程序实现的. Inserting 61 ----------------------------------------------------- case 1 <61> (若当前结点是根结点,则将其颜色设置为