您的位置:首页 > 其它

平衡二叉树(AVL)的创建、插入、删除

2017-09-11 12:24 387 查看
一、概念

平衡二叉树(下文称AVL)是满足每个结点的左右子树高度(亦称深度)之差在{0,1,-1}这个范围内的二叉排序树(二叉排序树也叫二叉搜索树)。


AVL的优势是在查找时避免了出现一般二叉排序树查找的最坏情况。但是AVL在经过插入或删除结点的操作之后可能出现不平衡的情况,所以每次插入或删除完之后要判断是否平衡,不平衡就需要rebalance.这会增加插入删除的复杂度。

二、AVL的创建

正常的有规律的创建方法(实际上是各种资料采用的方法)是将创建,
看成从NULL开始,一次次对原有的AVL的插入(显然只有一个结点的Tree一定是AVL)。


三、AVL的插入

1.方法:

先把结点按二叉排序树的结构正常插入,再由底向上逐级判断是否平衡,不平衡就rebalance. 插一次可能经过几次rebalance。(具体情况请往下读)


2.插入处的叶子节点的情况:



图1


显然

1) 插入处的叶子有且仅有这4种情况
2)对于②④来说,一定不影响原有树平衡
3)对于①③来说,不确定是否影响原有树的平衡;如果影响,不平衡点一定在结点A的祖先结点中(包括父亲节点,下文同)。
4)对于①③来说,我们要把这种不平衡的可能逐级传递给A的祖先结点,再逐级判断A的祖先节点 a.是否不平衡,不平衡需要rebalance,
之后b.是否有影响上一级平衡性的可能,有就需要继续传递这种可能。进行递归


3.不平衡节点的情况

!!注意:这里讨论的是三、2.4)中逐级往上,第一个出现不平衡的节点的情况。其他节点若不平衡都是依次逐级递归调整,讨论且只有讨论第一个出现的不平衡的节点的情况才有意义。

(1)插入前



图2
注:
LH:左子树高
RH:右子树高
EQ:左右子树等高
x:深度值


显然,

1)插入后第一个出现不平衡的节点在插入前有且仅有这两种情况
2)我们只需讨论其中一种情况,另一种同理可解


本文选择第一种,下文即根据第一种而展开

(2)插入后



图3
注:
DISEQ_LH:因为左子树过高而不平衡
DISEQ_RH:因为右子树过高而不平衡


显然

1)第一个出现不平衡的节点有且仅有这两种情况
2)有的书籍中将第一种情况称为”LL型“,第二种情况称为"LR"型


(3)对于”LL型“的讨论



图4


显然,

1)LL型有且仅有这两种情况
2)有的书籍将第一种情况称为"LL的一般型”,第二种称为“LL的简单型”,这很明显是不科学的,甚至是错误的叫法,
因为一般型不能包含简单型还叫一般吗?本文将第一种称为”LL的次简型“,第二种称为“LL的最简型”。
3)rebalance方法如下图(二者代码一致):




图5


(3)对于”LR型“的讨论



图6


显然

1)"LR型"有且仅有这两种情况
2)本文将第一种称为”LR的次简型“,第二种称为“LR的最简型”
3)rebalance方法如下图(二者代码不一致,主要在于平衡因子的改变不同):




图7


四、AVL的删除

1.方法:

1)删除:先找到要删除的结点;然后判断结点的子树情况,如果无子树,直接删除,如果有一个孩子,删除后将孩子结点接到父亲结点上,
如果有两个孩子,可以选择a.在左孩子中找到最大结点 b.在右孩子中找到最小结点 ,将找到的节点与要删除的结点的data替换,
然后问题转化为在删除结点的左子树中删除找到的结点。变成递归。
2)出现不平衡,即进行rebalance,删除一次可能rebalance多次


2.删除处的叶子节点的情况

!!注意,此处指的是四、1.1)中递归到最后删除叶子结点的情况[/b]



图8


显然,

1)删除处的叶子有且仅有这4种情况
2)对于②④来说,一定不影响原有树平衡
3)对于①③来说,不确定是否影响原有树的平衡;如果影响,不平衡点一定在结点A的祖先结点中(包括父亲节点,下文同)。
a.是否不平衡,不平衡需要rebalance, 之后b.是否有影响上一级平衡性的可能,有就需要继续传递这种可能。进行递归。


3.不平衡节点的情况

!!注意:这里讨论的是三、2.4)中逐级往上,第一个出现不平衡的节点的情况。其他节点若不平衡都是依次逐级递归调整,讨论且只有讨论第一个出现的不平衡的节点的情况才有意义。

(1)删除前



图9


显然,

1)删除后第一个出现不平衡的节点在插入前有且仅有这两种情况

2)我们只需讨论其中一种情况,另一种同理可解(本文选择第一种,下文即针对第一种情况而展开)

(2)删除后



图10


显然,

1)第一个出现不平衡的节点有且仅有这3种情况
2)对照前面的插入操作,我们知道,第一种不平衡情况称为”LL型“,第二种情况称为"LR"型,那么第三种呢?有的教材将其归为前两种之一,
那明显是错误的,请那么做的作者去看LL、LR型的定义。有的教材更差劲,甚至不讲AVL删除操作。我将第三种情况命名为“LE型”。


(3)对于”LL型“的讨论

操作同插入时的“LL型”,但请清楚具体情况与插入时不同


(4)对于”LR型“的讨论



图11


(5)对于”LE型“的讨论



图12
注:对于”LE型“,可以用"LL型"的操作旋转节点,也可以用"LR型“的操作旋转节点。(但注意过后平衡因子的改变与LL或LR不同),应用LL显然更简单。


五、源代码

enum BalanceFactor //平衡因子取值
{
DISEQ_RH = -2, //因为右子树高2不平衡
RH = -1, //右子树比左子树高1
EQ = 0,  //左右子树等高
LH =1,   //左子树比右子树高1
DISEQ_LH = 2 //因为左子树高2不平衡
};

typedef struct Tnode
{
BalanceFactor t_balancefacor;
float t_data;
struct  Tnode* lchild;
struct  Tnode* rchild;
}Tnode;

void createBBST(Tnode* &tree);
bool searchBBST(Tnode* tree, float search_data);
bool insertBBST(Tnode* &tree, float insert_data, bool &taller);
bool deleteBBST(Tnode* &tree, float delete_data, bool &shorter);
/*注意:AVL的插入和删除是有固定方法的,虽然还有其他手段也能使得插入后的AVL树平衡,但不是我们要探讨的*/

//(1)插入:按二叉搜索树的方法插入,再调平衡。
//      此种插入方法一共有四种失衡状态:LL,LR,RR,RL

//(2)删除:使用其按顺序的前导或顺序后继节点替换将要删除的节点,然后删除按顺序的前导或顺序后继节点。
//      此种删除方法就是在其左子树中找最大节点,或在右子树中找最小节点替换,(再次注意,两种方式得到的结果不同)
//      然后再删除左子树中的最大节点或右子树中的最小节点,
//      然后从第一个不平衡点开始,调平衡,找不平衡点,调平衡,构成递归。
//      以下提到的祖先节点包括父节点

void createBBST(Tnode* &tree)
{
printf("Please input a sequence of numbers for create a BBST (numbers are separated by blanks and the sequence ends with #.):\n");
float insert_data;
char buffer;
scanf("%f", &insert_data);
scanf("%c", &buffer);
//printf("%g ", insert_data);
bool taller = false;
while (buffer != '#'){
insertBBST(tree, insert_data,taller);
scanf("%f", &insert_data);
scanf("%c", &buffer);
//printf("%g ", insert_data);
}
}

bool searchBBST(Tnode* tree,float search_data)
//tree中找search_data, 找到返回true
{
if (tree == NULL)
{
return false;
}
else
{
if (search_data < tree->t_data)
{
return searchBBST(tree->lchild, search_data);
}
else if (search_data > tree->t_data)
{
return searchBBST(tree->rchild, search_data);
}
else
return true;
}
return true;
}
Tnode* AdjustRR(Tnode* anode)
{
Tnode* bnode = anode->rchild;
anode->rchild = bnode->lchild;
bnode->lchild = anode;

anode->t_balancefacor = EQ;
bnode->t_balancefacor = EQ;
return bnode;
}

Tnode* AdjustLL(Tnode* anode)
{
Tnode* bnode = anode->lchild;
anode->lchild = bnode->rchild;
bnode->rchild = anode;

anode->t_balancefacor = EQ;
bnode->t_balancefacor = EQ;
return bnode;
}
Tnode* AdjustRL(Tnode* anode)
{
Tnode* bnode = anode->rchild;
Tnode* cnode = bnode->lchild;
anode->rchild = cnode->lchild;
bnode->lchild = cnode->rchild;
cnode->lchild = anode;
cnode->rchild = bnode;
if (cnode->t_balancefacor == EQ) //最简单不平衡情况
{
anode->t_balancefacor = EQ;
bnode->t_balancefacor = EQ;
cnode->t_balancefacor = EQ;
}
else//次简单不平衡情况
{
if (cnode->t_balancefacor == LH)
{
anode->t_balancefacor = EQ;
bnode->t_balancefacor = RH;
cnode->t_balancefacor = EQ;
}
else if (cnode->t_balancefacor == RH)
{
anode->t_balancefacor = LH;
bnode->t_balancefacor = EQ;
cnode->t_balancefacor = EQ;
}

}

return cnode;
}
Tnode* AdjustLR(Tnode* anode)
{
Tnode* bnode = anode->lchild;
Tnode* cnode = bnode->rchild;
anode->lchild = cnode->rchild;
bnode->rchild = cnode->lchild;
cnode->lchild = bnode;
cnode->rchild = anode;

if (cnode->t_balancefacor == EQ)  //处理最简单不平衡情况
{
anode->t_balancefacor = EQ;
bnode->t_balancefacor = EQ;
cnode->t_balancefacor = EQ;
}
else//处理次简单不平衡情况
{
if (cnode->t_balancefacor == LH)
{
anode->t_balancefacor = RH;
bnode->t_balancefacor = EQ;
cnode->t_balancefacor = EQ;
}
else if (cnode->t_balancefacor == RH)
{
anode->t_balancefacor = EQ;
bnode->t_balancefacor = LH;
cnode->t_balancefacor = EQ;
}
}
return cnode;
}

bool insertBBST(Tnode* &tree, float insert_data, bool &taller)
//在tree中插入inser_data,  成功插入返回true
{
taller = false;  //多赋值,可能是冗余操作,后单步知并不冗余
bool inserted = false;
if (tree == NULL)
{
tree = (Tnode*)malloc(sizeof(Tnode));
tree->t_data = insert_data;
tree->lchild = tree->rchild = NULL;
tree->t_balancefacor = EQ;
taller = true;
inserted = true;
return inserted;
//return true;
}
else
{
if (insert_data < tree->t_data)
{
inserted = insertBBST(tree->lchild, insert_data, taller);

//最下面的节点
if (taller == true)
{
switch (tree->t_balancefacor)//判断在插入之前tree->t_balancefactor的值
{
case EQ:
tree->t_balancefacor = LH;
taller = true; //递归给上一级的taller
break;

case LH:  //走到此分支均是因为增加节点之后,不平衡。此处进行rebalance,并重置balancefactor

tree->t_balancefacor = DISEQ_LH;
//可能出现LR,也可能LL
//只能是这2种情况,因为前面有if(taller)限制,tree->lchild->balancefactor此刻就不能是EQ
//换一种有趣的说法是不能一次加两个节点,所以tree->lchild->balancefactor此刻不能是EQ
if (tree->lchild->t_balancefacor == RH)
{
/*LR类型处理并修改平衡因子*/
tree = AdjustLR(tree);
taller = false;
break;
}
else if (tree->lchild->t_balancefacor == LH)
{
/*LL类型处理并修改平衡因子*/
tree = AdjustLL(tree);
taller = false;
break;
}

case RH:
tree->t_balancefacor = EQ;
taller = false;
break;
}
}
return inserted;
}
else if (insert_data > tree->t_data)
{
inserted = insertBBST(tree->rchild, insert_data, taller);

if (taller == true)
{
switch (tree->t_balancefacor)//判断在插入之前tree->t_balancefactor的值
{
case EQ:
tree->t_balancefacor = RH;
taller = true; //递归给上一级的taller
break;

case LH:
tree->t_balancefacor = EQ;
taller = false;
break;

case RH:  //走到此分支均是因为增加节点之后,不平衡。此处进行rebalance,并重置balancefactor
tree->t_balancefacor = DISEQ_RH;

//可能出现LR,也可能LL
//只能是这2种情况,因为前面有if(taller)限制,tree->rchild->balancefactor此刻就不能是EQ
//换一种有趣的说法是不能一次加两个节点,所以tree->lchild->balancefactor此刻不能是EQ
if (tree->rchild->t_balancefacor == LH)
{
/*RL处理并修改平衡因子*/
tree = AdjustRL(tree);
taller = false;
break;
}
else  if (tree->rchild->t_balancefacor == RH)
{

/*RR处理并修改平衡因子*/
tree = AdjustRR(tree);
taller = false;
break;
}
}
}
return inserted;
}
else
{
return false;   //insert_data已存在,返回false
}
}
}

//虽然删除节点与插入的调整LL\LR\RR\RL的具体情况不一样,但是居然得到正确结果的操作并无不同
Tnode* AdjustLL_delete(Tnode* anode)
{
return AdjustLL(anode);
}
Tnode* AdjustRR_delete(Tnode* anode)
{
return AdjustRR(anode);
}
Tnode* AdjustLR_delete(Tnode* anode)
{
return AdjustLR(anode);
}
Tnode* AdjustRL_delete(Tnode* anode)
{
return AdjustRL(anode);
}
Tnode* AdjustLE_delete(Tnode* anode) //anode->balancefator == LH
{
Tnode* bnode = anode->lchild;
anode->lchild = bnode->rchild;
bnode->rchild = anode;

anode->t_balancefacor = LH;
bnode->t_balancefacor = RH;
return bnode;
}
Tnode* AdjustRE_delete(Tnode* anode) //anode->balancefator == RH
{
Tnode* bnode = anode->rchild;
anode->rchild = bnode->lchild;
bnode->lchild = anode;

anode->t_balancefacor = RH;
bnode->t_balancefacor = LH;
return bnode;
}

/*******************************************************************************************
1.删除
(1)Deleting a node with 0 children nodes 直接删除
(2)Deleting a node with 1 children nodes 将另一个子树接上
(3)Deleting a node with 2 children nodes :
Replace the(to - delete) node with its in - order predecessor or in - order successor
Then delete the in - order predecessor or in - order successor

2.调平衡
The actionPos (action position) in a delete operation is the parent node of the "deleted" node
不平衡点可能且只可能是被删除的节点的祖先节点
*********************************************************************************************/
bool deleteBBST(Tnode* &tree, float delete_data, bool& shorter)
{

shorter = false;
bool deleted = false;
if (tree == NULL)
{
return false; //删除失败
}
else if(delete_data < tree->t_data)
{
deleted = deleteBBST(tree->lchild, delete_data, shorter);

if (shorter)
{
switch (tree->t_balancefacor) //由原来祖先节点的balancefactor修改删除操作后现在祖先节点的balancefactor
{
case EQ:
tree->t_balancefacor = RH;
shorter = false;
return deleted;
case LH:
tree->t_balancefacor = EQ;
shorter = true;
return deleted;
case RH:   //走到此分支均是因为删除节点之后,不平衡。此处进行rebalance,并重置balancefactor

if ( tree->rchild->t_balancefacor == LH)
{
//delete 的 RL处理并修改平衡因子
tree = AdjustRL_delete(tree);
shorter = true;
return deleted;
}
else if (tree->rchild->t_balancefacor == RH)
{
//delete 的 RR处理并修改平衡因子
tree = AdjustRR_delete(tree);
shorter = true;
return deleted;

}
//比增加节点rebalance多此情况,是因为删除一个节点可能等效于使得另一分支增加了多个节点
else if (tree->rchild->t_balancefacor == EQ)
{
//delete 的 RE处理并修改平衡因子
tree = AdjustRE_delete(tree);
shorter = false;
return deleted;
}
}
}
}
else if (delete_data > tree->t_data)
{
deleted = deleteBBST(tree->rchild, delete_data, shorter);

if (shorter)
{
switch (tree->t_balancefacor)//由原来祖先节点的balancefactor修改删除操作后现在祖先节点的balancefactor
{
case EQ:
tree->t_balancefacor = LH;
shorter = false;
return deleted;
case RH:
tree->t_balancefacor = EQ;
shorter = true;
return deleted;
case LH:  //走到此分支均是因为删除节点之后,不平衡。此处进行rebalance,并重置balancefactor

if (tree->lchild->t_balancefacor == LH)
{
//delete 的 LL处理并修改平衡因子
tree = AdjustLL_delete(tree);
shorter = true;
return deleted;
}
else if (tree->lchild->t_balancefacor == RH)
{
//delete 的 LR处理并修改平衡因子
tree = AdjustLR_delete(tree);
shorter = true;
return deleted;
}
else if (tree->lchild->t_balancefacor == EQ)
{
//delete 的 LE处理并修改平衡因子
tree = AdjustLE_delete(tree);
shorter = false;
return deleted;
}
}
}
}

else if (delete_data == tree->t_data)
{
//下面的前三个if为最简单操作,最后一种情况递归到上面if(shorter)里
//   if(tree->lchild == tree->rchild == NULL) 会出现逻辑错误

if (tree->lchild == NULL && tree->rchild == NULL)
{
tree = NULL;
shorter = true;
deleted = true;
return deleted;
}
else if ((tree->lchild != NULL) && (tree->rchild == NULL))
{
tree = tree->lchild;
shorter = true;
deleted = true;
return deleted;
}
else if ((tree->rchild != NULL) && (tree ->lchild == NULL))
{
tree = tree->rchild;
shorter = true;
deleted = true;
return deleted;
}
else //被删除的节点即存在左子树也存在右子树
{
Tnode* inorder_predecessor = tree->lchild; //用来记录顺序前导节点
while (inorder_predecessor->rchild != NULL)
{
inorder_predecessor = inorder_predecessor->rchild;
}
tree->t_data = inorder_predecessor ->t_data;  //替换要删除的节点
//原问题转化为在tree->lchild中删除inorder_predecessor指向的节点
deleted = deleteBBST(tree->lchild, inorder_predecessor->t_data, shorter);

if (shorter)
{
switch (tree->t_balancefacor) //由原来祖先节点的balancefactor修改删除操作后现在祖先节点的balancefactor
{
case EQ:
tree->t_balancefacor = RH;
shorter = false;
return deleted;
case LH:
tree->t_balancefacor = EQ;
shorter = true;
return deleted;
case RH:   //走到此分支均是因为删除节点之后,不平衡。此处进行rebalance,并重置balancefactor
if (tree->rchild->t_balancefacor == LH)
{
//delete 的 RL处理并修改平衡因子
tree = AdjustRL_delete(tree);
shorter = true;
return deleted;
}
else if (tree->rchild->t_balancefacor == RH)
{
//delete 的 RR处理并修改平衡因子
tree = AdjustRR_delete(tree);
shorter = true;
return deleted;

}
//比增加节点rebalance多此情况,是因为删除一个节点可能等效于使得另一分支增加了多个节点
else if (tree->rchild->t_balancefacor == EQ)
{
//delete 的 RE处理并修改平衡因子
tree = AdjustRE_delete(tree);
shorter = false;
return deleted;
}
}
}
return deleted;
}
}
}


参考:1

但请注意,这个资料里举例的图存在错误
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐