从二叉排序树到平衡二叉树再到红黑树系列2

上篇博客主要讲述了二叉排序树的基本概念和插入删除操作,必须再次说明的是:在一棵高度为h的二叉排序树上,实现动态集合操作查询,插入和删除的运行时间均为O(h)。

可见二叉树的基本操作效率取决于树的形态,当然树的高度越低越好,显然树分布越均匀,高度越低。那么,问题来了?对于给定的关键字序列,如何构造一棵形态匀称的二叉排序树。这种匀称的二叉排序树就称为平衡二叉树。

平衡二叉树定义:平衡二叉树或为空树,或其上任意一个节点,节点的左右子树高度差不超过1.     通常将二叉树上所有结点的左右子树的高度之差称为平衡因子。

构造平衡二叉树的常用算法有AVL树和红黑树等。其中,AVL树保持平衡的机制是靠平衡因子和旋转,而红黑树保持平衡的机制是靠 节点颜色约束和旋转,事实上,红黑树并不追求完全平衡,只能算部分平衡:没有路径能多余其他路径2倍长,但红黑树能以O(log2 n)的时间复杂度进行查询删除插入操作。 本篇博客先介绍AVL,下篇博客再讲解红黑树。

构造AVL树的基本思想:每当插入一个新结点时,首先检查是否因插入而破坏了树的平衡性;在保持二叉排序树的特性同时,(也就是说平衡二叉树得首先保证它是二叉排序树)调整最小不平衡子树各结点之间的指向,以达到新的平衡。<所谓最小不平衡子树就是指离插入点最近,且平衡因子大于1的结点作为根的子树,简而言之:就是从新插入结点位置开始向根节点寻找,第一个由平衡变为不平衡的结点>

与二叉排序树相比,平衡二叉树插入节点后还要保证插入后既要保证有序,又要保证平衡。那么保证的方法就是:旋转

插入新节点N导致平衡二叉树不再平衡,最小不平衡子树的根为A,插入位置不同,插入后调整节点平衡因子和指向也不同。可以归纳为如下4种情况(如图所示):

注:图中节点用圈表示,子树用长方形表示,代表不止一个结点,可能一个,可能多个节点,长方形长度代表子树高度。红色标记为指针指向变化示意。

1> LL,新插入节点在A左孩子的左子树上:右旋,如图所示,当新添加节点N时,节点A的平衡因子bf(blancefactor)由1变为2,为了书写清晰直观描述为:A.bs = 1-->2(以下格式同)  而B.bs = 0--->1。为了保持平衡,这时需要节点A需要绕B向右旋转。

形象点说,就是指节点A本来就已经快要不平衡了(bs=1,左子树比右子树高),这个时候其左子树又添加一个结点,这不是压死骆驼的最后一根稻草么。。。这个时候就需要让树往右边旋转,降低节点A的高度。而节点B 添加N之前 bs=0,表示还有承受能力,这个时候给它加加担子,让他由小兵变将军,升到根节点去,这样树就变为平衡了。废话有点多,但是好理解。具体调整过程见代码。

//右旋转处理函数
void R_Rotate( BSTree &p)
{
	BSTree lc;
	lc=p->lchild;
	p->lchild=lc->rchild;
	lc->rchild=p;
	p=lc;
}

2>RR,新插入节点在A右孩子的右子树上:左旋;如图所示。和右旋原理类似,本来右子树就高,再来一节点,不得不左旋。

//左旋转处理函数
void L_Rotate(BSTree &p)
{
	BSTree rc;
	rc=p->rchild;
	p->rchild=rc->lchild;
	rc->lchild=p;
	p=rc;
}

3>LR,新插入节点在A左子树的右子树上,先左旋再右旋,准确点说是在A左子树的右子树的(左子树或右子上)

相比于操作1>和操作2>,操作3>相对复杂。这样操作的原因在于:插入新的节点N之前,根节点A和其左子树根节点B都是平衡因子不为0的节点:也就是说A.bf=1 B.bf=-1;

即他们与不平衡只差一步之遥了,再添加一个节点,且都是添加在他们的A的左子树,B的右子树的左子树下,他们要被压死了,这个时候,根节点A对子节点B说,你来当根节点。B一看,我的不平衡因子也不是0,没法当啊;于是,B左旋,把C顶上去。对A说,我不能当根节点,但是C可以,于是,再一次绕C右旋转,A下来,C当上了根节点。

,为什么C能当根节点?因为添加前C的平衡因子为0,即使添加一个节点后,它与不平衡依然还有一步之遥。

具体过程见代码

//插入操作时左平衡旋转处理函数---包含平衡因子的修改
void LeftBalance(BSTree &T)
{
	BSTree lc,rd;
	lc=T->lchild;
	switch(lc->bf)    //检查T的左子树的平衡度,判断是操作1>还是操作3>,并作相应的平衡处理
	{
		case LH:      //操作1>:做单右旋处理
				T->bf=lc->bf=EH;//1 新结点插入在T的左子树上,先修改平衡因子再右旋
			    R_Rotate(T);
				break;
		case RH:      //操作3>
				rd=lc->rchild;//-1 新结点插入在T的左孩子的右子树上,
				switch(rd->bf)
				{	//修改T及左孩子的平衡因子
					case LH:T->bf=RH;//新节点插在rd下作为左子树
							lc->bf=EH;//
							break;
					case EH:T->bf=lc->bf=EH;//
							break;
					case RH:T->bf=EH;//新节点插在rd下作为右子树
							lc->bf=LH;
							break;
				}

				rd->bf=EH;
				L_Rotate(T->lchild);//对T的左子树左旋处理
				R_Rotate(T);//再对T做右旋处理
	}
}

4>RL,新插入节点在A右子树的左子树上,先右旋再左旋。过程和LR是类似的,不再赘述。

直接贴代码

//插入操作时右平衡旋转处理函数
void RightBalance(BSTree &T)
{
	BSTree rc,ld;
	rc=T->rchild;
	switch(rc->bf)     //检查T的右子树的平衡度,并作相应的平衡处理
	{
		case RH:T->bf=rc->bf=EH;
			    L_Rotate(T);
				break;
		case LH:ld=rc->lchild;
				switch(ld->bf)
				{
					case LH:T->bf=EH;
							rc->bf=RH;
							break;
					case EH:T->bf=rc->bf=EH;
							break;
					case RH:T->bf=LH;
							rc->bf=EH;
							break;
				}
				ld->bf=EH;
				R_Rotate(T->rchild);
				L_Rotate(T);
	}
}
时间: 2024-10-08 02:50:01

从二叉排序树到平衡二叉树再到红黑树系列2的相关文章

从二叉排序树到平衡二叉树再到红黑树系列3

这篇博客主要讲解B树及其插入删除操作,并给出操作的流程图以达到清晰易懂的目的,尽管标题是从二叉排序树到平衡二叉树再到红黑树系列3,没有B树二字,但他们都是动态查找树,所以我将他们归为一个系列. B树是为磁盘或其他直接存取的辅助存储设备而设计的一种平衡搜索树.它以一种很自然的方式推广了二叉搜索树,B树与红黑树的不同之处在于B树结点的孩子不限于最多为2,而是可以有数个到数千个不定.因为结点的分支更多,因而相比红黑树,高度更小. B树的定义有如下两种,但殊途同归. 定义形式一(以度 t 定义): 一棵

从二叉排序树到平衡二叉树再到红黑树系列1

最近想写一些关于红黑树的博客,既想写的全面,又直观,但是又不知道从哪里入手.斟酌再三,还是从最简单的二叉排序树开始写. 二叉排序树(Binary Sort Tree)又叫二叉查找树.它是一种特殊结构的二叉树.其或为空树,或具备下列性质: (1)若它的左子树不为空,则左子树上所有结点的值均小于它的根节点的值. (2)若它的右子树不为空,则左子树上所有结点的值均大于它的根节点的值. 显然,它的中序遍历就是一个递增的有序序列. 定理:在一棵高度为h的二叉搜索树上,动态集合上的操作serach,minm

数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)

树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: BST树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中: 如果BST树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B树 的搜索性能逼近二分查找:但它比连续内存空间的二分查找的优点是,改变BST树结构 插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销: 如:

从二叉树到2-3-4树再到红黑树

直接进入正题: 一.如何从数组生成一个二叉树 假设数组为:{ 30, 13, 7, 43, 23, 12, 9, 33, 42, 21, 18, 6, 3, 50 },我们不对数组排序,直接生成二叉树. 创建流程: 1.将第一数作为根节点: 2.插入13,13小于30,放在30的左边子节点. 3.插入7,7小于30,7小于13,放在13的左边子节点. 4.插入43,43大于30,放在30的右边子节点. 5.放入23,23小于30,23大于13,放入13的右边子节点. 6.放入12,12小于30,

再论红黑树

红黑树: 红黑树(Red Black Tree) 是一种自平衡二叉查找树 : l 每个节点或者是黑色,或者是红色. l 根节点是黑色. l 每个叶子节点是黑色. l 如果一个节点是红色的,则它的子节点必须是黑色的. l 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点. 红黑树的各种操作的时间复杂度是O(log2N). 红黑树 vs AVL 红黑树的查询性能略微逊色于AVL树,因为他比avl树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的avl树最多多一次比较,但是,红

为什么要有红黑树?什么是红黑树?画了20张图,看完这篇你就明白了

为什么要有红黑树 想必大家对二叉树搜索树都不陌生,首先看一下二叉搜索树的定义: 二叉搜索树(Binary Search Tree),或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉排序树. 从理论上来说,二叉搜索树的查询.插入和删除一个节点的时间复杂度均为O(log(n)),已经完全可以满足我们的要求了,那么为什么还要有红黑树呢? 我们来看一个例

红黑树之添加节点和创建

红黑树之插入节点 红黑树的性质 红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色.在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求: 节点是红色或黑色. 根节点是黑色. 每个叶节点(这里的叶节点是指NULL节点,在<算法导论>中这个节点叫哨兵节点,除了颜色属性外,其他属性值都为任意.为了和以前的叶子节点做区分,原来的叶子节点还叫叶子节点,这个节点就叫他NULL节点吧)是黑色的. 每个红色节点的两个子节点都是黑色.(从每个叶子到根的所有路径上不能有两个连续的

为什么红黑树的效率比较高

红黑树属于平衡二叉树.它不严格是因为它不是严格控制左.右子树高度或节点数之差小于等于1,但红黑树高度依然是平均log(n),且最坏情况高度不会超过2log(n). 红黑树(red-black tree) 是一棵满足下述性质的二叉查找树: 1. 每一个结点要么是红色,要么是黑色. 2. 根结点是黑色的. 3. 所有叶子结点都是黑色的(实际上都是Null指针,下图用NIL表示).叶子结点不包含任何关键字信息,所有查询关键字都在非终结点上. 4. 每个红色结点的两个子节点必须是黑色的.换句话说:从每个

数据结构系列(5)之 红黑树

本文将主要讲述平衡二叉树中的红黑树,红黑树是一种我们经常使用的树,相较于 AVL 树他无论是增加还是删除节点,其结构的变化都能控制在常树次:在 JDK 中的 TreeMap 同样也是使用红黑树实现的: 一.结构概述 红黑树是在AVL 树平衡条件的基础上,进一步放宽条件,从而使得红黑树在动态变化的时候,其结构的变化在常数次:其标准大致可以表示为: 任一节点左.右子树的高度,相差不得超过两倍. 同他的名字,红黑树的节点是有颜色的,如图所示: 其性质如下: 树根始终为黑色 外部节点均为黑色(图中的 l