AVL树插入操作InsertAVL的实现

AVL树是非常重要的一种数据结构,这里实现了在AVL树中的插入操作,包括插入后整个树的自平衡。

这里有几点值得注意的地方:

1).左旋L_Rotate与右旋R_Rotate操作:

这两个操作传递进来的参数是以TreeNode*&的形式传递进来的,也就是说传递的是指针的引用,效果等价于传递二级指针

如果不加入&,则在函数内部更改的是形参的指向,因为实际上函数调用时,如果不采用引用传递,则会构造一个与原T指向同一个地方的临时变量指针,在X_Rotate的内部也是对这个临时变量进行操作,等到返回后对原来的T一点影响都没有。因此对于指针的操作,如果说需要在某个函数内更改这个指针的指向,则要么传递二级指针,要么传递指针的引用。

2).在LR型或RL型中:

以LR型为例,要根据不平衡点的左子树的根的右孩子rd的bf值来确定T与lc的bf值,其中rd->bf会出现等于0的情况。

这种情况只会出现在rc才是新插入的节点,也就是说lc->right在原来未插入时是NULL,只有在这种情况下才会显现在rc->bf=0,树却增高的情况。

一点小小的总结:

AVL树第一次接触感觉很复杂,转来转去,四个形状,其实思考清楚后整个思路还是很简单的:

首先是LL型与RR型:

这两种情况是最简单的,只需要简单的右旋/左旋即可.

以LL型为例子:对T右旋后,实际上就是将T->left->right接到T的left上,并将T->left->right改为接上T。

RR型也是如此。

然后是LR型与RL型:

这两种情况复杂的原因在于,仅仅是右旋/左旋,T的bf仍不会变化。

以LR型为例子:

问题出现在右旋后将T->left->right接到T的left并不会改变T的bf。

但实际上LR型可以看做这样一个过程:先将他转换为LL型。

也就是说,如果把插入节点插入到T->left的左子树上,就转变为第一个问题了。

现在的问题在于怎么把插入在T->left的右子树上的节点看做插在左子树上呢,只要我们对T->left进行一次左旋。

我们现在将T->left看做一个树的根节点,对这个T’进行一次左旋,根据左旋的规则发现原本插在T‘->right上的节点现在被旋转到T‘->right上了,而T->left的位置现在被T‘->left->right所占据,现在的问题变为了LL型,则只要想问题一一样进行一次右旋就可以了。

这也就是LR型的整个过程。

对RL型也是如此。

struct TreeNode
{
	int val;
	int bf;
	struct TreeNode* left;
	struct TreeNode* right;
};
class Solution
{
public:
	int InsertAVL(TreeNode*& T,int val,bool& taller)
	{
		if(!T)
		{
			T=new TreeNode;
			T->bf=0;
			T->left=T->right=NULL;
			T->val=val;
			taller=true;
		}
		else
		{
			if(val==T->val)
			{
				taller=false;
				return 0;
			}
			else if(val<T->val)//left
			{
				if(!InsertAVL(T->left,val,taller))
					return 0;
				if(taller)
				{
					switch(T->bf)
					{
					case -1:
						taller=false;T->bf=0;break;
					case 0:
						taller=true;T->bf=1;break;
					case 1:
						LeftBalance(T);taller=false;break;
					}
				}
			}
			else
			{
				if(!InsertAVL(T->right,val,taller))
					return 0;
				if(taller)
				{
					switch(T->bf)
					{
					case 1:
						taller=false;T->bf=0;break;
					case 0:
						taller=true;T->bf=-1;break;
					case -1:
						RightBalance(T);taller=false;break;
					}
				}
			}
		}
		return 1;
	}
private:
	void R_Rotate(TreeNode*& p)//注意这里是传递的指针的引用,效果等价于传递二级指针
	{
		TreeNode* lc=p->left;
		p->left=lc->right;
		lc->right=p;
		p=lc;
	}
	void L_Rotate(TreeNode*& p)
	{
		TreeNode* rc=p->right;
		p->right=rc->left;
		rc->left=p;
		p=rc;
	}
	void LeftBalance(TreeNode*& T)
	{
		TreeNode* lc=T->left;
		switch(lc->bf)
		{
		case 1:
			T->bf=lc->bf=0;R_Rotate(T);break;
		case -1:
			TreeNode* rd=lc->right;
			switch(rd->bf)
			{
			case 1:
				lc->bf=0;T->bf=-1;break;
			case 0://注意这里rd->bf=0.这种情况是rd这个节点就是新插入的节点,它的左右子树都为空,所以rd->bf=0.只有这种情况才会出现rd->bf=0
				lc->bf=T->bf=0;break;
			case -1:
				lc->bf=1;T->bf=0;break;
			}
			rd->bf=0;
			L_Rotate(T->left);
			R_Rotate(T);
			break;
		}
	}
	void RightBalance(TreeNode*& T)
	{
		TreeNode* rc=T->right;
		switch(rc->bf)
		{
		case -1:
			rc->bf=T->bf=0;break;
		case 1:
			TreeNode* ld=rc->left;
			switch(ld->bf)
			{
			case -1:
				rc->bf=0;T->bf=1;break;
			case 0:
				rc->bf=T->bf=0;break;
			case 1:
				rc->bf=-1;T->bf=0;break;
			}
			ld->bf=0;
			R_Rotate(T->right);
			L_Rotate(T);
			break;
		}
	}
};

  

原文地址:https://www.cnblogs.com/lxy-xf/p/11311851.html

时间: 2024-10-10 14:26:16

AVL树插入操作InsertAVL的实现的相关文章

AVL树插入和删除

一.AVL树简介 AVL树是一种平衡的二叉查找树. 平衡二叉树(AVL 树)是一棵空树,或者是具有下列性质的二叉排序树:    1它的左子树和右子树都是平衡二叉树,    2且左子树和右子树高度之差的绝对值不超过 1. 定义平衡因子(BF)为该结点左子树的高度减去右子树的高度所得的高度差:AVL 树任一结点平衡因子只能取-1,0,1: 二.AVL树插入 插入:先查找被插入元素,如果存在,则不操作:如果不存在,则插入. 插入后就是调整和选择的问题. 我们先看一下我们会面临怎么样的问题: 离插入点最

Phone List(简单的字典树插入操作)

Phone List Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 11655    Accepted Submission(s): 3970 Problem Description Given a list of phone numbers, determine if it is consistent in the sense th

AVL树相关操作

#include <iostream> using namespace std; //AVL树的节点 template<typename T> class TreeNode { public: TreeNode() :lson(NULL), rson(NULL), freq(1), hgt(0){} T data;//值 int hgt;//以这个结点为根的树的高度 int freq;//相同点的频率,我是不知道 TreeNode* lson, *rson;//左右儿子的地址 };

AVL树插入删除

写了好久,感觉插入和删除麻烦些,插入也就4种情况,但只要写两个函数,左左和右右的,左右的情况是以根节点的左子树为头进行一次右右旋转,使它变成左左的情况,再左左旋转下就下,右左的也一样: 另外就是删除,先是判断要删除的节点右儿子是否为空,是空,直接删,否则找到它最左边的儿子来替代它,然后就是高度的更新,重新的旋转... 哎,真实花了我好长时间,不过终于写完了.大致感觉没啥问题了吧,有的话以后再改吧. #include <iostream> #include <cstdio> #inc

AVL树插入(Python实现)

建立AVL树 1 class AVLNode(object): 2 def __init__(self,data): 3 self.data = data 4 self.lchild = None 5 self.rchild = None 6 self.parent = None 7 self.bf = 0 8 9 class AVLTree(object) 10 def __init__(self,li=None) 11 self.root = None 12 if li: 13 for va

avl树的操作证明

以下用大O表示节点,ABC表示三个集合. 仅分析左子树的情况,因为对称,右子树的情况一样. 插入节点前 O /     \ O        A   /    \ B       C 插入节点后: O /     \ O        A   /    \ B       C / O 此时造成了最高节点的不平衡,说明了B+2 - A = 2;另外可以知道B = C,考虑B<C,那么在插入节点前最高点就已经不平衡了,考虑B > C,那么最高的左子树就已经不平衡了,而不应该考虑最高点.所以此时可以

AVL树的初步生成与插入操作

平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树.构造与调整方法 平衡二叉树的常用算法有红黑树.AVL.Treap等. 最小二叉平衡树的节点的公式如下 F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量. AVL是最先发明的

AVL树非递归插入删除思路

AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增加和删除可能需要通过一次或多次树旋转来重新平衡这个树.AVL树得名于它的发明者G.M. Adelson-Velsky和E.M. Landis,他们在1962年的论文<An algorithm for the organization of information>中发表了它. 节点的平衡因子是它的左子树的高度减去它的右子树的

AVL树的插入与删除

AVL 树要在插入和删除结点后保持平衡,旋转操作必不可少.关键是理解什么时候应该左旋.右旋和双旋.在Youtube上看到一位老师的视频对这个概念讲解得非常清楚,再结合算法书和网络的博文,记录如下. 1.1 AVL 的旋转 一棵AVL树是其每个节点的左子树和右子树的高度差最多为1的二叉查找树(空树高度定义为-1).AVL树插入和删除时都可能破坏AVL的特性,可以通过对树进行修正来保证特性,修正方法称为旋转. 下面以4个插入操作为例,说明不同旋转对应的场景. 1.1.1 LL-R 插入结点为6,沿着