图解平衡二叉搜索树
本博文使用图文描述了平衡二叉搜索树的插入过程:
1: 寻找插入点
2:向上回溯寻找失去平衡的节点 (状态不等于EH的节点)
3:旋转
平衡二叉搜索树
平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。 数值关系,右孩子的值 > 当前节点的值 > 左孩子的值。
平衡二叉搜索树节点的状态
1:左子树比右子树高 LH
2:左子树和右子树一样高 EH
3:右子树比左子树高 RH
如上图每个节点的状态如下。
TreeNode 的定义
static final class TreeNode<T> { TreeStatus treeStatus = TreeStatus.EH; T value; TreeNode<T> left; TreeNode<T> right; TreeNode<T> parent; public TreeNode(T value) { this.value = value; } public TreeNode(T value, TreeNode<T> p) { this.value = value; this.parent = p; } public String toString() { return "value=" + value.toString(); } }
搜索插入点
以向平衡二叉树插入105为例。
搜索过程
105 gt 90 搜索90的右子树
105 gt 100 搜索100的右子树
105 lt 130 搜索130的左子树
105 lt 107 搜索107的左子树
107的左子树为空,停止搜索, 105为107的左孩子。
插入新点节之后搜索途中的节点的状态发生改变,需要回溯更改每个节点的状态。
107节点的状态为EH,105为107的左孩子,所以107的状态更改为LH,
130节点的状态为EH,107为130的左孩子,所以130的状态更改为LH,
100节点的状态为RH, 130 为100的右孩子, 所以 100节点失去平衡。
向上回溯的图解如下。
情况1: 回溯途中所有节点的状态都为EH, 那么树的平衡性不会发生改变。
直观一点的图。
向上回溯的路径为:
在插入54节点之前,所有节点的状态为EH,但是在插入54节点之后。
51 由EH---> RH
55 由EH--->LH
50 由EH---> RH
100 由EH--->LH
如果me是p的左孩子,那么p的状态改为LH,
如果me是p的右孩子,那么p的状态改为RH。
p=p.parent ;
me=me.parent;
情况2:回溯的途中遇到了第一个状态不为EH的节点,假设该节点为pp。
由pp,p来决定pp树是否失去平衡。
假设pp的状态为LH,
如果p为pp的左孩子,那么pp树将会失去平衡。 如果p的状态为LH,那么进行LL旋转,如果p的状态为RH,那么进行LR旋转。
如果p为pp的右孩子,那么pp树将维持平衡,并且pp的状态需要修改为EH.
平衡二叉树有6个插入点:
当插入点为1或者2时, 引起LL旋转。
当插入点为3或者4时,引起LR旋转。
当插入点为5或者6时,不会引发旋转。
由(pp.treeStatus, p.treeStatus)来决定做那种旋转。。。
镜像的pp的状态为RH;
下面开始讲旋转:
LL 旋转
pp为失衡的节点。 p为pp的左孩子,me为p的左孩子, xpp为pp的父节点。
步骤1: pr = p.right;
步骤2: p.pright = pp; pp.parent = p;
步骤3: pp.left = pr ; pr.parent = pp ;
步骤4: p.parent=xpp , 确定p是xpp的左孩子还是右孩子
重点说明 如果xpp为空,则p节点为新的root节点。
旋转之后 p和pp节点的状态均为EH。
LR旋转
pp为失衡的节点。 p为pp的左孩子,me为p的右孩子, xpp为pp的父节点。
步骤1 : mel =me.left; mer= me.right
步骤2: me.left = p ; me.right = pp; p.parent = me, pp.parent = me ;
步骤3: p.right = mel ; pp.left = mer ; mel.parent = p ; mer.parent = pp ;
步骤4: me.parent = xpp ; 确定me是xpp的左孩子还是右孩子
重点说明 如果xpp为空,则me节点为新的root节点。
状态的改变:
如果me的状态为LH 那么p的状态为EH , pp的状态为RH;
如果me的状态为RH 那么p的状态为LH, pp的状态为EH ;
如果me的状态为EH 那么p的状态为EH , pp的状态为EH;
旋转完成之后me的状态一定为EH。
RR旋转和LL旋转是镜像关系。
RL和LR是镜像关系。
本博文讲述了平衡二叉搜索树的插入过程:
1: 寻找插入点
2:向上回溯寻找失去平衡的点pp (pp,p,me)。 (即向上回溯寻找到状态不等于EH的点)
3:旋转
如果对您理解平衡二叉搜索树有帮助还请帮忙点赞。
如果您发现博文的描述有错误或者漏洞,请发表评论。
转载请注明博文出处。
实现见 https://gitee.com/tuerqidi/avl
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
该如何理解数据仓库的建设?
什么是数据仓库 数据仓库,最早由比尔·恩门(Bill Inmon)于1990年提出,主要功能是将组织或企业里面的联机事务处理(OLTP)所累积的大量数据,透过数据仓库理论所特有的储存架构,进行系统的分析整理,以利于各种分析方法如联机分析处理(OLAP)、数据挖掘(Data Mining)的进行,并进而支持如决策支持系统(DSS)、主管信息系统(EIS)的创建, 帮助决策者能快速有效的从大量数据中分析出有价值的信息。 目前, 被广泛接受的数据仓库的定义是由Bill Inmon在1991年出版的 "Building the Data Warehouse"一书中所提出的,其定义如下: 数据仓库(Data Warehouse)是一个面向主题的(Subject Oriented)、集成的(Integrated)、反映历史变化(Time Variant)、相对稳定的(Non-Volatile)的数据集合,用于支持管理决策(Decision Making Support)。 其实,在大数据时代,随着机器学习和人工智能的兴起,这个定义需要做一些补充:数据仓库不只是用于构建支持管理决策的商业智能BI的基...
- 下一篇
Vue3全局可替换内容模态框
模态框是常用的组件,常用在需要显示较少但是重要内容的时候。它需要立即抓到用户的焦点,所以常设计为一个居中的对话框和一个处在背后的黑色半透明遮罩。整体的样式不会有多少变化,但是内容经常变化。 对于单个页面来说,一个模态框的内容可能不会变化,所以可以写一个静态的组件放在页面中,需要时控制它的显示和隐藏即可。但是对于多个页面,内容不同,如果每个页面都放一个模态框组件,那就有点浪费资源且不够灵活。还有一种场景,就是内容是不确定的,就需要模态框可以动态的创建元素并显示。同时希望可以通过一个函数调用,且得到用户关闭模态框时的反馈。 举个例子,首页可以访问,但是有些页面需要登录后进入。点击一个需要登录的页面后弹出登录模态框,用户输入登录信息后,代码在点击处继续,调用接口登录后进入相应的页面,这一条操作链路不能断。 总结一下,现在的核心需求有: 单一的全局组件 动态创建内容 全局函数控制显隐 关闭时返回数据 除此以外,最好还可以: 既可以作为全局组件,也可以作为普通组件 内容和遮罩可以有不同的显示隐藏动画 okay,接下来用Vue3来实现这样一个组件。 基本组件 定义modal组件。 template...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7,8上快速安装Gitea,搭建Git服务器
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Docker使用Oracle官方镜像安装(12C,18C,19C)