码迷,mamicode.com
首页 > 其他好文 > 详细

AVL树插入操作InsertAVL的实现

时间:2019-08-06 21:29:16      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:引用   private   div   情况   treenode   需要   临时   结构   ase   

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;
		}
	}
};

  

AVL树插入操作InsertAVL的实现

标签:引用   private   div   情况   treenode   需要   临时   结构   ase   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有 京ICP备13008772号-2
迷上了代码!