我已经实现了一个AVL树,但是我遇到了问题。
假设我有以下树:
添加另一个节点后:
现在我必须将node5旋转到左边:
但在轮换之后,它仍然是不平衡的。
我在哪里犯了错误?
答案 0 :(得分:19)
所呈现的场景符合this Wikipedia描述中的 Right-Left 案例。
您的错误是您一次旋转不平衡节点(5
),而不先执行其子树的旋转。
通常将P
作为不平衡节点,L
作为其左子树,R
作为其右子树,插入时应遵循以下规则:
balance(N) = Depth(Nleft) - Depth(Nright)
if (balance(P) > 1) // P is node 5 in this scenario
{
if (balance(L) < 0)
{
rotate_left(L);
}
rotate_right(P);
}
else if (balance(P) < -1) // P is node 5 in this scenario
{
if (balance(R) > 0) // R is node 11 in this scenario
{
rotate_right(R); // This case conforms to this scenario
}
rotate_left(P); // ... and of course this, after the above
}
所以有时需要进行两次轮换,有时只需要一次。
在Wikipedia处可以很好地看到它:
顶行显示需要两次旋转的情况。当一次旋转足够时,中间行显示可能的情况。其他旋转将任何顶行场景转换为中间行场景。
特别是对于这棵树:
添加7
后:
5
的余额 2
。这符合上面在伪代码中标记了注释的场景,也符合维基百科图片中的顶行场景(右侧的场景)。因此,在5
左旋之前,其右子树11
需要右旋:
它变成了:
只有现在,这是一个简单的案例(维基百科图片中的中间右侧场景),在5
处通过一次左旋转恢复平衡:
树又变得平衡了:
答案 1 :(得分:0)
让我试着更全面地分析, 对于作为avl树的二叉树,每个节点从任何最左边的叶子到任何最右边的叶子的高度差必须位于{-1,0,1}内。
AVL的插入:
AVL插入有四种情况 - 二 L - R. R - R. R - L
现在, 案例(a)。 [如果余额&gt; 1] L-L(左 - 左)节点X违反{-1,0,1}约束和 离开高度比右边 - 左边是L 有一个左子子Y,其左高度大于右..再次L 动作 - 顺时针旋转Y.即。 一次正确的轮换。
情况(b)(L -R情况)假设要插入一些Z节点,对于Z,首先评估它,放置它的叶子,左边或右边。对,如果更重,如果减重则留下。 比方说,Z&#39 ;,新节点,wt(Z&#39;)&gt; wt(Z),即Z&#39;作为Z的右子插入,L - R的情况,整个链接ZZ&#39;逆时针旋转,现在是L-L情况,因此使用上述情况(a)解决。即。 一个左,然后一个右旋。
案例(c)[如果余额&lt; -1](R - R情况)类似地,R - R情况,只是应用二进制搜索规则进行调整,这种情况有效。即。 一个左旋转。
情况(d)(R-L情况)首先将其转换为R-R情况,因此使用上述情况(c)求解。即。 一个向右然后一个向左旋转。