AVL 树
二叉搜索树的性能问题
在二叉搜索树中的查找和删除操作的时间复杂度是 o(h)级别的,可见二叉搜索树的高度直接影响了二叉搜索树的使用性能,但是随着不断的添加和删除操作,二叉搜索树的左右子树高度可能会存在差距太大的情况,所以在删除和添加之后应该对二叉搜索树进行调整,使用最小的调整次数把二叉搜索树调整为左右子树高度相近。
二叉搜索树的问题
在添加、删除元素过程中二叉树可能会退化为链表,下面举例说明
-
添加
- 在添加元素的时候安装升序或者降序来添加元素。
-
删除
- 在对BST树元素删除的过程中,BST子树之间的高度差越来越大,影响BST树的性能。
平衡二叉搜索树
如果能够在对BST树删除和添加操作之后对BST子树之间的高度差进行检测,如果大于预计的值就对BST树进行调整使之子树之间的高度差减小,这样BST树就能一直保持着较高的效率了。
具体应用
- AVL 树
- 红黑树
AVL
基本概念
- 平衡因子
- 某个节点的左右子树的高度差
- 每个节点的平衡因子只能是 1、-1 、0
- 也就是每个节点的左右子树高度差不能超过1
- 如果节点的平衡因子超过 1 就是失衡的状态
- 也就是每个节点的左右子树高度差不能超过1
- 搜索、添加、删除的时间复杂度是 O(logN)
导致失衡的原因
添加导致的失衡
AVL树的调整
- LL 右旋转 (单旋)
- RR 左旋转 (单旋)
- LR RL (双旋转)
具体的实现
- 添加节点导致的失衡
- 从添加的这个节点开始找,开始调整所有失衡节点中高度最低的那个节点
- 只要是高度最低节点重新回复平衡,那么整个树也就恢复了。
举例
约定:
- 失去平衡高度最低的那个节点叫做 grand节点
- 失去平衡且高度最低的那个节点的最高子节点叫做 parent节点
- 新添加的节点叫做 node节点
RR 左旋转
思路
此时是13这个节点出现了不平衡,需要对它进行旋转操作。选择操作达成的效果就是让 13 这个节点向左旋转一下,对于树的操作而言:
- 调整13这个节点的右子树为 14节点的左子树
- 调整14这个节点的左子树为13
- 把14节点的父节点调整为13节点的父节点。
- 调整 13 节点的父节点
- 调整 14 节点左子树的父节点
Code
grand.right = parent.left
parent.left.parent = grand
grand.parent = parent
parent.parent = grand.parent
parent.left = grand
LL 右旋转
思路
此时是13这个节点出现了不平衡,需要对它进行旋转操作。选择操作达成的效果就是让 13 这个节点向右旋转一下,对于树的操作而言:
- 调整13这个节点的左子树为 12节点的右子树
- 调整12这个节点的左子树为13
- 把12节点的父节点调整为13节点的父节点
- 调整 11 节点的父节点
- 调整 12 右子树的父节点
Code
grand.left = parent.right
parent.right.parent = grand
grand.parent = patent
parent.parent = grand.parent
parent.right = grand
LR 双旋转
思路
此时是 16 节点出现了不平衡,然后对于16节点来说恢复平衡的方案是进行两次旋转,13左旋转之后 15右旋转,对于树的操作而言:
-
13左旋
- 13 节点的右子树 设置为 15节点的左子树
- 调整 15 节点左子树的父节点
- 15 节点的左子树 设置为 13节点
- 16 节点的左子树 设置为 15节点
- 调整 15节点的父节点
- 调整 13 节点的父节点
-
15右旋
- 16 节点的左子树 设置为 15节点的右子树
- 调整 15节点右子树的父节点
- 15 节点的右子树 设置为 16节点
- 调整 16 节点的父节点
- 15 节点的父节点 设置为 16节点的父节点
Code
参考 左右旋转
RL 双旋转
思路
此时是 13 节点出现了不平衡,然后对于13节点来说恢复平衡的方案是进行两次旋转,15右旋转之后 13左旋转,对于树的操作而言:
-
15右旋
- 15 节点的左子树 设置为 14节点的右子树
- 调整 14节点右子树的父节点
- 14 节点的右子树 设置为 15节点
- 调整15节点的父节点
- 13 节点的右子树 设置为 14节点
- 调整 14 节点的父节点
-
13左旋
- 13 节点的右子树 设置为 14节点的左子树
- 14 节点的父节点 设置为 13节点的父节点
- 14 节点的左子树 设置为 13节点
- 调整 1 节点左子树的父节点
- 调整 13 节点的父节点
Code
参考 左右旋转