平衡二叉树
树>二叉树>二叉搜索树>二叉平衡树
参考文献
1 简介
概念
- 满足二叉搜索树的定义
- 所有结点的平衡因子的绝对值都不超过1,即平衡因子只能是1,0,-1三个值。
- 如果任何节点的平衡因子为1,则意味着左子树比右子树高一级。
- 如果任何节点的平衡因子为0,则意味着左子树和右子树包含相等的高度。
- 如果任何节点的平衡因子是-1,则意味着左子树比右子树低一级。

复杂性
| 算法 |
平均情况 |
最坏情况 |
| 空间 |
o(n) |
o(n) |
| 搜索 |
o(log n) |
o(log n) |
| 插入 |
o(log n) |
o(log n) |
| 删除 |
o(log n) |
o(log n) |
优势
- AVL树能防止二叉树偏斜,控制二叉搜索树的高度。高度为h的二叉搜索树中的所有操作所花费的时间是O(h)。
- 如果普通二叉搜索树变得偏斜(即最坏的情况),它可以扩展到O(n)。
- 通过将该高度限制为log n,AVL树将每个操作的上限强加为O(log n),其中n是节点的数量
2 操作
基本操作
插入
- AVL树中的插入的执行方式与在二叉搜索树中执行的方式相同。
- 它可能会导致违反AVL树属性,因此树可能需要平衡。可以通过应用旋转来平衡树。
删除
- 删除也可以按照在二叉搜索树中执行的相同方式执行。
- 删除也可能会扰乱树的平衡,因此,使用各种类型的旋转来重新平衡树。
- 删除节点的步骤如下:
- 以前三种情况为基础尝试删除节点,并将访问节点入栈。
- 如果尝试删除成功,则依次检查栈顶节点的平衡状态,遇到非平衡节点,即进行旋转平衡,直到栈空。
- 如果尝试删除失败,证明是第四种情况。这时先找到被删除节点的右子树最小节点并删除它,将访问节点继续入栈。
- 再依次检查栈顶节点的平衡状态和修正直到栈空。
3 操作——平衡
左旋
为了使树平衡,使用的手段有 : 左旋和右旋。右旋, 即是顺时针旋转。左旋,即是逆时针旋转。
- 左旋。加入新节点 99 后,节点 66 的左子树高度为 1,右子树高度为 3,此时平衡因子为 -2。为保证树的平衡,此时需要对节点 66 做出旋转,因为右子树高度高于左子树,对节点进行左旋操作,
- 节点的右孩子替代此节点位置
- 右孩子的左子树变为该节点的右子树
- 节点本身变为右孩子的左子树


右旋
- 右旋。
- 节点的左孩子代表此节点
- 节点的左孩子的右子树变为节点的左子树
- 将此节点作为左孩子节点的右子树。


插入过程的四种旋转
删除与插入节点的四种旋转方式类似
| 插入方式 |
描述 |
旋转方式 |
| LL |
在 A 的左子树的根节点的左子树上插入节点而破坏平衡 |
右旋转 |
| RR |
在 A 的右子树的根节点的右子树上插入节点而破坏平衡 |
左旋转 |
| LR |
在A的左子树的根节点的右子树上插入节点而破坏平衡 |
先左旋后右旋 |
| RL |
在 A 的右子树的根节点的左子树上插入节点而破坏平衡 |
先右旋后左旋 |
LL单次右旋
- 由于在A的左子树的根结点的左子树上插入结点F(LL),需进行一次的向右的顺时针旋转操作

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
|
Tree LL_rotate(Tree node){ Tree parent=NULL,son; parent=node->parent; son=node->lchild; if (son->rchild!=NULL) son->rchild->parent=node; node->lchild=son->rchild; update_depth(node); son->rchild=node; son->parent=parent; if (parent!=NULL){ if (parent->lchild==node){ parent->lchild=son; }else{ parent->rchild=son; } } node->parent=son; update_depth(son); return son; }
|
RR单次左旋
- 在 A 的右子树的根节点的右子树上插入节点而破坏平衡。需要进行一次左旋操作。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
Tree RR_rotate(Tree node){ Tree parent=NULL,son; parent=node->parent; son=node->rchild; if (son->lchild!=NULL){ son->lchild->parent=node; } node->rchild=son->lchild; update_depth(node); son->lchild=node; son->parent=parent; if (parent!=NULL){ if (parent->lchild==node){ parent->lchild=son; }else{ parent->rchild=son; } } node->parent=son; update_depth(son); return son; }
|
LR先左旋后右旋
- 在A的左子树的根节点的右子树上插入节点F而破坏平衡。需要先进行子树的左旋再进行A节点的右旋。

1 2 3 4 5 6
|
Tree LR_rotate(Tree node){ RR_rotate(node->lchild); return LL_rotate(node); }
|
RL先右旋后左旋
- 在 A 的右子树的根节点的左子树上插入节点F而破坏平衡。需要先进行子树右旋,然后进行A节点的左旋。

1 2 3 4 5 6
|
Tree RL_rotate(Tree node){ LL_rotate(node->rchild); return RR_rotate(node); }
|
4 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| typedef int ElementType;
struct AVLNode{
int depth;
Tree parent;
ElementType val;
Tree lchild;
Tree rchild;
AVLNode(int val=0) { parent = NULL; depth = 0; lchild = rchild = NULL; this->val=val; } };
|