平衡二叉树

前言

在关键字排列随机的情况下,二叉排序树的平均查找长度和 l o g n log n logn是等数量级的。在某些情况下,尚需在构成二叉排序树的过程中进行“平衡化”处理,使其成为平衡二叉树。
如果任何初始化序列构成的二叉排序树都是平衡二叉树,因为平衡二叉树上任何结点的左右子树的深度之差都不超过1,则可以证明它的深度和 l o g n log n logn是同数量级别的(其中n为结点个数)。由此,它的平均查找长度也和 l o g n log n logn同数量级。

平衡二叉树定义及性质

平衡二叉树(Balanced Binary Tree 或 Height-Balanced Tree)又称AVL树。它或者是一棵空树,或者是具有下列性质的二叉树:
(1) 它的左子树和右子树都是平衡二叉树;
(2) 它的左子树和右子树的深度之差的绝对值不超过1。若将二叉树上结点的平衡因子定位为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有节点的平衡因子只可能是-1、0和1。

平衡二叉排序树的插入操作

一般情况下,假设由于在二叉排序树上插入结点而失去平衡的最小树根结点的指针为a(即a是离插入结点最近,且平衡因子绝对值超过1的祖先节点),则失去平衡后进行调整的规律可归纳为下列4种情况:
(1) 单向右旋平衡处理:由于在*a的左子树根结点的左子树上插入结点,*a的平衡因子由1增至2,致使以*a为根的子树失去平衡,则需再进行一次向右的顺时针旋转操作。如下图所示:
请添加图片描述

(2) 单向左旋平衡处理:由于在*a的右子树根结点的右子树上插入结点,*a的平衡因子由-1增至-2,致使以*a为根的子树失去平衡,则需再进行一次向左的逆时针旋转操作。如下图所示:
请添加图片描述

(3) 双向旋转(先左后右)平衡处理:由于在*a的左子树根结点的右子树上插入结点,*a的平衡因子由1增至2,致使以*a为根结点的子树失去平衡,则需进行两次旋转(先左旋后右旋)操作。如下图所示:
请添加图片描述

(4) 双向旋转(先右后左)平衡处理:由于在*a的右子树根结点的左子树上插入结点,*a的平衡因子由-1增至-2,致使以*a为根结点的子树失去平衡,则需进行两次旋转(先右旋后左旋)操作。如下图所示:
请添加图片描述

上述4中情况,(1)和(2)对称,(3)和(4)对称。旋转操作的正确性容易由"保持二叉排序树的特性:中序遍历所得关键字序列由小至大有序"证明。当平衡的二叉排序树因插入结点而失去平衡时,仅需对最小不平衡子树进行旋转即可。因为经过旋转处理之后的子树深度和插入之前相同,因而不影响插入路径上所有祖先结点的平衡度。
在平衡的二叉排序树BBST上插入一个新的数据元素e的递归算法可描述如下:
(1) 若BBST为空树,则插入一个数据元素为e的新结点作为BBST的根结点,树的深度加1。
(2) 若e的关键字和BBST的根结点的关键字相等,则不进行插入。
(3) 若e的关键字小于BBST的根结点的关键字,而且在BBST的左子树中不存在和e有相同关键字的结点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度+1时,分别就下列不同情况处理之:
(a) BBST的根结点的平衡因子为-1(右子树的深度大于左子树的深度):则将根结点的平衡因子更改为0,BBST的深度不变;
(b) BBST的根结点的平衡因子为0(左子树和右子树的深度相等):则将根结点的平衡因子更改为1,BBST的深度+1;
© BBST的根结点的平衡因子为1(左子树的深度大于右子树的深度:若BBST的左子树根结点的平衡因子为1,则需进行单向右旋平衡处理,并且在右旋后,将根结点和其右子树根结点的平衡因子更改为0,树的深度不变;若BBST的左子树根结点的平衡因子为-1,则需进行先向左、后向右的双向旋转平衡处理,并且在旋转处理之后,修改根结点和其左子树、右子树根结点的平衡因子,树的深度不变;
(4) 若e的关键字大于BBST的根结点的关键字,而且在BBST的右子树不存在于e有相同关键字的结点,则将e插入在BBST的右子树上,并且当插入之后的右子树深度+1时,分别就不同的情况处理之。其处理操作和步骤3中所述相对称,这里不展开说明。
由于平衡二叉排序树的插入代码实现较复杂,有兴趣的同学可以自行参考**《数据结构》的9.2.1 二叉排序树和平衡二叉树小节**学习。

平衡二叉排序树的创建

将二叉排序树转换成平衡树

public TreeNode balanceBST(TreeNode root) {List<Integer> sortedList = new ArrayList();traverseByInorder(root, sortedList);return createTree(sortedList, 0, sortedList.size()-1);
}private void traverseByInorder(TreeNode root, List<Integer> sortedList) {if(root == null) {return;}traverseByInorder(root.left, sortedList);sortedList.add(root.val);traverseByInorder(root.right, sortedList);
}private TreeNode createTree(List<Integer> sortedList, int left, int right) {int mid = (left + right) >> 1;TreeNode root = new TreeNode(sortedList.get(mid));if(left <= mid -1) {root.left = createTree(sortedList, left, mid -1);}if(right >= mid+1) {root.right = createTree(sortedList, mid+1, right);}return root;
}

将有序数组转换平衡二叉排序树

public TreeNode sortedArrayToBST(int[] nums) {return createTree(nums, 0, nums.length - 1);
}private TreeNode createTree(int[] nums, int left, int right) {if(nums.length == 0) {return null;}int mid = (left + right) >> 1;TreeNode root = new TreeNode(nums[mid]);if(left<= mid -1) {root.left = createTree(nums, left, mid - 1);}if(right>= mid +1) {root.right = createTree(nums, mid +1, right);}return root;
}

将有序链表转换成平衡二叉排序树

public TreeNode sortedListToBST(ListNode head) {return createTree(head, null);
}private TreeNode createTree(ListNode leftNode, ListNode rightNode) {if(leftNode == rightNode) {return null;}ListNode middleNode = getMiddleNode(leftNode, rightNode);TreeNode root = new TreeNode(middleNode.val);root.left = createTree(leftNode, middleNode);root.right = createTree(middleNode.next, rightNode);return root;
}private ListNode getMiddleNode(ListNode left, ListNode right) {ListNode fast = left;ListNode slow = left;while (fast != right && fast.next != right) {fast = fast.next.next;slow = slow.next;}return slow;
}

判断一棵树是否是平衡二叉树

判断一棵树是不是平衡二叉树,就是判断这棵树是否满足平衡二叉树的性质:
(1) 它的左子树和右子树都是平衡二叉树;
(2) 它的左子树和右子树的深度之差的绝对值不超过1。若将二叉树上结点的平衡因子定位为该结点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有节点的平衡因子只可能是-1、0和1。

public boolean isBalanced(TreeNode root) {if(root == null) {return true;}return Math.abs(height(root.left) - height(root.right))<=1 && isBalanced(root.left) && isBalanced(root.right);
}private int height(TreeNode root) {if(root == null) {return 0;}return Math.max(height(root.left), height(root.right)) + 1;
}
public boolean isBalanced(TreeNode root) {return height(root) >= 0;
}
private int height(TreeNode root) {if(root == null) {return 0;}int leftHeight = height(root.left);int rightHeight = height(root.right);if(leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {return -1;}return Math.max(leftHeight, rightHeight) + 1;
}

参考

《数据结构》 严蔚敏 吴伟民 著 9.2.1 二叉排序树和平衡二叉树
https://zhuanlan.zhihu.com/p/163515903 平衡二叉树专题
https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/ 108. 将有序数组转换为高度平衡的二叉搜索树
https://leetcode.cn/problems/convert-sorted-list-to-binary-search-tree/ 109. 有序链表转换为高度平衡的二叉搜索树
https://leetcode.cn/problems/balanced-binary-tree/ 110. 平衡二叉树
https://leetcode.cn/problems/balance-a-binary-search-tree/description/ 1382. 将二叉搜索树变平衡的二叉搜索树

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/273213.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

注意!!墙裂推荐几个好用的实用小工具!一定会用到的!

前言 在开发的世界里&#xff0c;面对各种挑战和问题时&#xff0c;拥有一套合适的工具箱至关重要。这不仅能提升我们的工作效率&#xff0c;还能让复杂的任务变得简单&#xff0c;甚至在解决棘手问题的同时&#xff0c;还能让我们的心情略微舒畅。众所周知&#xff0c;有用的…

Java - Spring MVC 实现跨域资源 CORS 请求

据我所知道的是有三种方式&#xff1a;Tomcat 配置、拦截器设置响应头和使用 Spring MVC 4.2。 设置 Tomcat 这种方式就是引用别人封装好的两个 jar 包&#xff0c;配置一下web.xml就行了。我也并不推荐&#xff0c;这里放两个我在网上找到的配置相关文章&#xff0c;感兴趣可…

052-WEB攻防-XSS跨站脚本攻击反射型存储型DOM型标签闭合输入输出JS代码解析

052-WEB攻防-XSS跨站脚本攻击&反射型&存储型&DOM型&标签闭合&输入输出&JS代码解析 #知识点&#xff1a; 1、XSS跨站-输入输出-原理&分类&闭合 2、XSS跨站-分类测试-反射&存储&DOM 演示案例&#xff1a; ➢XSS跨站-输入输出-原理&…

微信小程序如何实现下拉刷新

1.首先在你需要实现下拉刷新页面的json文件中写入"enablePullDownRefresh": true。 2.在js文件的onPullDownRefresh() 事件中实现下拉刷新。 实现代码 onPullDownRefresh() {console.log(开始下拉刷新)wx.showNavigationBarLoading()//在标题栏中显示加载图标this.d…

HarBor私有镜像仓库安装部署

环境准备 #>>> redis $ yum -y install redis $ systemctl enable --now redis $ vim /etc/redis.conf modify: bind <ipaddress> $ systemctl restart redis#>>> nfs $ yum -y install nfs-utils $ mkdir -p /data/harbor $ vi /etc/exports /data/h…

css--浮动

一. 浮动的简介 在最初&#xff0c;浮动是用来实现文字环绕图片效果的&#xff0c;现在浮动是主流的页面布局方式之一。 二. 元素浮动后的特点 &#x1f922;脱离文档流。&#x1f60a;不管浮动前是什么元素&#xff0c;浮动后&#xff1a;默认宽与高都是被内容撑开&#xff0…

Text Field文本输入框

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 Text Field文本输入框 一、最基本的本文输入框1、基础示例2、一些表单属性3、验证 二、多行文本 一、最基本的本文输入框 1、基础示例 import {Box, TextField} from "…

学术论文GPT的源码解读与二次开发:从ChatPaper到gpt_academic

前言 本文的前两个部分最早是属于此旧文的《学术论文GPT的源码解读与微调&#xff1a;从ChatPaper到七月论文审稿GPT第1版》&#xff0c;但为了每一篇文章各自的内容更好的呈现&#xff0c;于是我今天做了以下三个改动 原来属于mamba第五部分的「Mamba近似工作之线性Transfor…

修改简化docker命令

修改|简化docker命令 使用命令打开 .bashrc 文件&#xff1a; vim ~/.bashrc在文件中添加类似以下行来创建别名&#xff1a; # 查看所有容器 alias disdocker images # 查看运行容器 alias dpsdocker ps # 查看所有容器 alias dpsadocker ps -a # 停止容器 alias dsdocker s…

PostgreSQL数据优化——死元组清理

最近遇到一个奇怪的问题&#xff0c;一个百万级的PostgreSQL表&#xff0c;只有3个索引。但是每次执行insert或update语句就要几百ms以上。经过查询发现是一个狠简单的问题&#xff0c;数据库表死元组太多了&#xff0c;需要手动清理。 在 PG 中&#xff0c;update/delete 语句…

PCM会重塑汽车OTA格局吗(1)

目录 1.汽车OTA概述 2.ST如何考虑OTA&#xff1f; 2.1 Stellar四大亮点 2.2 PCM技术视角下的OTA 3.小结 1.汽车OTA概述 随着智能网联汽车的飞速发展&#xff0c;汽车OTA也越来越盛行&#xff1b; 目前来讲OTA分为FOTA和SOTA(Software-over-the-air)两种&#xff0c;区别…

AI新工具 百分50%算力确达到了GPT-4水平;将音乐轨道中的人声、鼓声、贝斯等音源分离出来等

1: Pi 百分50%算力确达到了GPT-4水平 Pi 刚刚得到了巨大的升级&#xff01;它现在由最新的 LLMInflection-2.5 提供支持&#xff0c;它在所有基准测试中都与 GPT-4 并驾齐驱&#xff0c;并且使用不到一半的计算来训练。 地址&#xff1a;https://pi.ai/ 2: Moseca 能将音乐…

【CSS面试题】高度塌陷问题及解决

什么情况下产生 (when 父盒子没有定义高度&#xff0c;但是子元素有高度&#xff0c;希望用子盒子撑起父盒子的高度&#xff0c;但是子盒子添加了浮动属性之后&#xff0c;父盒子高度为0 <template><div class"father"><div class"son"&…

HarmonyOS 数据持久化 关系型数据库之 查询逻辑编写

前面两篇文章 HarmonyOS 数据持久化 关系型数据库之 初始化操作 和 HarmonyOS 数据持久化 关系型数据库之 增删改逻辑编写 我们已经编写了 初始化 和 增删改 操作的基本逻辑 最后 收尾一下查询的函数 我们还是打开编辑器 然后 打开项目 找到 我们正在写的这个 relationalClass…

力扣---简化路径

给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &#xff08;以 / 开头&#xff09;&#xff0c;请你将其转化为更加简洁的规范路径。 在 Unix 风格的文件系统中&#xff0c;一个点&#xff08;.&#xff09;表示当前目录本身&#xff1b;此外…

白皮书发布|超融合运行 K8s 的场景、功能与优势

目前&#xff0c;不少企业都使用虚拟化/超融合运行 Kubernetes 和容器化应用。一些用户可能会有疑惑&#xff1a;既然 Kubernetes 可以部署在裸金属上&#xff0c;使用虚拟化不是“多此一举”吗&#xff1f; 在电子书《IT 基础架构团队的 Kubernetes 管理&#xff1a;从入门到…

【STA】SRAM / DDR SDRAM 接口时序约束学习记录

1. SRAM接口 相比于DDR SDRAM&#xff0c;SRAM接口数据与控制信号共享同一时钟。在用户逻辑&#xff08;这里记作DUA&#xff08;Design Under Analysis&#xff09;&#xff09;将数据写到SRAM中去的写周期中&#xff0c;数据和地址从DUA传送到SRAM中&#xff0c;并都在有效时…

NoSQL--3.MongoDB配置(Linux版)

目录 2.2 Linux环境下操作 2.2.1 传输MongoDB压缩包到虚拟机&#xff1a; 2.2.2 启动MongoDB服务&#xff1a; 2.2 Linux环境下操作 2.2.1 传输MongoDB压缩包到虚拟机&#xff1a; &#xff08;笔者使用XShell传输&#xff09; 如果不想放在如图的路径&#xff0c;删除操作…

嵌入式系统

一、基本概念 嵌入式系统是以应用为中心、以计算机技术为基础&#xff0c;并将可配置与可裁剪的软、硬件集成于一体的专用计算机系统&#xff0c;需要满足应用对功能、可靠性、成本、体积和功耗方面的严格要求。从计算机角度看&#xff0c;嵌入式系统是指嵌入各种设备及应用产品…

MongoDB开启事务

MongoDB开启事务 配置单节点。到路径C:\Program Files\MongoDB\Server\4.0\bin 使用记事本以管理员权限打开文件mongod.cfg添加如下配置&#xff1a; replication:replSetName: rs02. 重启MongoDB服务 3. 重启后执行命令 rs.initiate()