二叉搜索树的平衡--AVL树和树的旋转
二叉搜索树只有保持平衡时其查找效率才会高。
要保持二叉搜索树的平衡不是一件易事。不过还是有一些非常经典的办法可以做到,其中最好的方法就是将二叉搜索树实现为AVL树。
AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the organization of information" 中发表了它。AVL树是一种特殊类型的二叉树,它的每个结点都保存一份额外的信息:结点的平衡因子。
结点的平衡因子 = 左子树的高度 - 右子树的高度
插入和删除操作都会导致AVL树的自我调整(自我平衡),使得所有结点的平衡因子保持为+1、-1或0。
当子树的根结点的平衡因子为+1时,它是左倾斜的(left-heavy)。
当子树的根结点的平衡因子为 -1时,它是右倾斜的(right-heavy)。
一颗子树的根结点的平衡因子就代表该子树的平衡性。
保持所有子树几乎都处于平衡状态,AVL树在总体上就能够基本保持平衡。
AVL树的基本查找、插入结点的操作和二叉树的操作一样。但是,当向AVL树中插入一个结点后,还有一些额外的工作要做。首先,必须计算因插入操作对平衡因子带来的改变。其次,如果任何平衡因子变成了+/-2,就必须从这个结点开始往下重新平衡这颗树,这个重新平衡的过程就称为旋转。
AVL树的旋转
旋转操作用来重新平衡树的某个部分。通过重新安排结点 ,使结点之间的关系始终保持左子结点小于父结点,父结点小于右子结点。使得该树仍然是一颗二叉搜索树。旋转过后,旋转子树中的所有结点的平衡因子都为+1、-1或0。
AVL树的旋转类型有4种, 分别是LL(left-left)旋转、LR(left-right)旋转、RR(right-right)旋转和RL(right-left)旋转。
为方便理解在何时执行哪一种旋转,设x代表刚插入AVL树中的结点,设A为离x最近且平衡因子更改为2的绝对值的祖先。可以归纳为下面4种处理情况:
LL旋转
如下图所示,当x位于A的左子树的左子树上时,执行LL旋转。
设left为A的左子树,要执行LL旋转,将A的左指针指向left的右子结点,left的右指针指向A,将原来指向A的指针指向left。
旋转过后,将A和left的平衡因子都改为0。所有其他结点的平衡因子没有发生变化。
LR旋转
当x位于A的左子树的右子树上时,执行LR旋转。
设left是A的左子结点,并设A的子孙结点grandchild为left的右子结点。
要执行LR旋转,将left的右子结点指向grandchild的左子结点,grandchild的左子结点指向left,A的左子结点指向grandchild的右子结点,再将grandchild的右子结点指向A,最后将原来指向A的指针指向grandchild。
执行LR旋转之后,调整结点的平衡因子取决于旋转前grandchild结点的原平衡因子值。
如果grandchild结点的原始平衡因子为+1,就将A的平衡因子设为-1,将left的平衡因子设为0。
如果grandchild结点的原始平衡因子为0,就将A和left的平衡因子都设置为0。
如果grandchild结点的原始平衡因子为-1,就将A的平衡因子设置为0,将left的平衡因子设置为+1。
在所有的情况下,grandchild的新平衡因子都是0。所有其他结点的平衡因子都没有改变。
RR旋转
当x位于A的左子树的右子树上时,执行RR旋转。
RR旋转与LL旋转是对称的关系。
设A的右子结点为Right。要执行RR旋转,将A的右指针指向right的左子结点,right的左指针指向A,原来指向A的指针修改为指向right。
完成旋转以后,将A和left的平衡因子都修改为0。所有其他结点的平衡因子都没有改变。
RL旋转
当x位于A的右子树的左子树上时,执行RL旋转。
RL旋转与LR旋转是对称的关系。
设A的右子结点为right,right的左子结点为grandchild。要执行RL旋转,将right结点的左子结点指向grandchild的右子结点,将grandchild的右子结点指向right,将A的右子结点指向grandchild的左子结点,将grandchild的左子结点指向A,最后将原来指向A的指针指向grandchild。
执行RL旋转以后,调整结点的平衡因子取决于旋转前grandchild结点的原平衡因子。这里也有三种情况需要考虑:
如果grandchild的原始平衡因子值为+1,将A的平衡因子更新为0,right的更新为-1;
如果grandchild的原始平衡因子值为 0,将A和right的平衡因子都更新为0;
如果grandchild的原始平衡因子值为-1,将A的平衡因子更新为+1,right的更新为0;
在所有情况中,都将grandchild的新平衡因子设置为0。所有其他结点的平衡因子不发生改变。
来源:https://www.cnblogs.com/idreamo/p/8308336.html
二叉搜索树的平衡--AVL树和树的旋转的更多相关文章
- 二叉搜索树的平衡--AVL树和树的旋转(图解)
二叉搜索树只有保持平衡时其查找效率才会高. 要保持二叉搜索树的平衡不是一件易事.不过还是有一些非常经典的办法可以做到,其中最好的方法就是将二叉搜索树实现为AVL树. AVL树得名于它的发明者 G.M. ...
- 把二叉搜索树转化成更大的树 · Convert BST to Greater Tree
[抄题]: 给定二叉搜索树(BST),将其转换为更大的树,使原始BST上每个节点的值都更改为在原始树中大于等于该节点值的节点值之和(包括该节点). Given a binary search Tree ...
- LIntcode---将二叉搜索树转成较大的树
Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original B ...
- [LC]235题 二叉搜索树的最近公共祖先 (树)(递归)
①题目 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的祖先 ...
- Java实现 LeetCode 530 二叉搜索树的最小绝对差(遍历树)
530. 二叉搜索树的最小绝对差 给你一棵所有节点为非负值的二叉搜索树,请你计算树中任意两节点的差的绝对值的最小值. 示例: 输入: 1 \ 3 / 2 输出: 1 解释: 最小绝对差为 1,其中 2 ...
- 动态平衡二叉搜索树的简易实现,Treap 树
http://blog.csdn.net/qichi_bj/article/details/8232048
- 算法二叉搜索树之AVL树
最近学习了二叉搜索树中的AVL树,特在此写一篇博客小结. 1.引言 对于二叉搜索树而言,其插入查找删除等性能直接和树的高度有关,因此我们发明了平衡二叉搜索树.在计算机科学中,AVL树是最先发明的自平衡 ...
- 数据结构之二叉搜索树、AVL自平衡树
前言 最近在帮公司校招~~ 所以来整理一些数据结构方面的知识,这些知识呢,光看一遍理解还是很浅的,看过跟动手做过一遍的同学还是很容易分辨的哟~ 一直觉得数据结构跟算法,就好比金庸小说里的<九阳神 ...
- 二叉树、二叉搜索树、平衡二叉树、B树、B+树的精确定义和区别探究
概述 关于树的概念很多,B树,B+树,红黑树等等. 但是你去翻翻百度百科,或者用百度或者谷歌搜索一下中文的树结构的介绍,全都是狗屁.没有哪个中文网站是真正精确解释树的定义的,尤其是百度百科. 下面我要 ...
随机推荐
- Mac平台下部署UE4工程到iOS设备的流程
1.开发环境 UE4.Xcode.iOS版本情况如下: 1.UE4:当前最新版本Unreal Engine 4.17.2. 2.Xcode:当前最新版本Xcode9.0. 3.iOS:当前最新版本iO ...
- Idea中类上有叉的解决方法
idea中类的头上出现X解决办法 ctrl+alt+s 在弹出的菜单上选择Compiler下的Excludes 右边会有 移除掉,点击ok, 重启idea就可以了
- unshift() 方法将一个或多个元素添加到数组的开头,并返回新数组的长度
var arr = [1, 2]; arr.unshift(0); //result of call is 3, the new array length //arr is [0, 1, 2] arr ...
- 无法在正在进行内容生成时调用 StartAt
刚遇到一个奇怪的问题,用户点击创建销售订单的时候,弹出个 无法在正在进行内容生成时调用 StartAt,查看详细报错. ystem.InvalidOperationException: 无法在正在进行 ...
- 吴裕雄 python深度学习与实践(11)
import numpy as np from matplotlib import pyplot as plt A = np.array([[5],[4]]) C = np.array([[4],[6 ...
- AngularJS学习笔记(一)
一.基本指令 1.ng-app=" " 指令初始化一个 AngularJS 应用程序,定义angularJS的使用范围; tips:一个页面里创建多个 ng-app 手动加载即可: ...
- 20175314 《Java程序设计》第三周学习总结
20175314 <Java程序设计>第三周学习总结 教材学习内容总结 编程语言的发展事是从面向机器(汇编.机器)到面向过程(C)再到面向对象(Java) 成员变量: 1.成员变量定义在类 ...
- hdu 4714 树+DFS
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4714 本来想直接求树的直径,再得出答案,后来发现是错的. 思路:任选一个点进行DFS,对于一棵以点u为 ...
- C++类有继承时,析构函数必须为虚函数
C++类有继承时,析构函数必须为虚函数.如果不是虚函数,则使用时可能存在内在泄漏的问题. 假设我们有这样一种继承关系: 如果我们以这种方式创建对象: SubClass* pObj = new SubC ...
- 结构体指offsetof宏详细解析
1.#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER) (include/linux/stddef.h) ...