标签:引用 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;
}
}
};
标签:引用 private div 情况 treenode 需要 临时 结构 ase
原文地址:https://www.cnblogs.com/lxy-xf/p/11311851.html