【数据结构与算法分析】0基础带你学数据结构与算法分析11--AVL树

news2024/11/25 12:27:01

目录

二分查找

AVL 树

AVL 的平衡因子

AVL 的插入操作

单旋转

双旋转

对 AVL 树插入的总结

AVL 的移除操作


如果给定一个序列,你将如何在这个序列中查找一个给定元素 target,当找到时返回该元素的迭代器,否则返回末尾迭代器。首先排除时间复杂度 O(N) 的朴素算法,这不是本文的重点。

二分查找

二分法 (Dichotomy) 是一种思想,将一个整体事物分割成两部分,这两部分必须是互补事件,即所有事物必须属于双方中的一方且互斥。如此我们就可以在 O(1) 的时间内将问题大小减半。

二分查找 (binary search),又称折半查找,这是一种可以在 O(log⁡N)时间复杂度下完成查找的算法。二分查找要求序列必须是有序的,才能正确执行:将序列划分为两部分,如果中间值大于 target,意味着这之后的值都大于 target,需要继续向前找;如果中间值小于 target,意味着这之前的所有值都小于 target,需要继续向后找。

AVL 树

上一篇介绍树时分析了 BST 中为什么很容易发生不平衡现象。在极端情况下,只有一个 leaf 的树,在查找元素时其时间复杂度退化为 O(N) 。

为了防止 BST 退化为链表,必须保证其可以维持树的平衡,一次需要有一个 平衡条件 (balanced condition)。如果每个结点都要求其左右子树具有相同的高度,显然是不可能的,因为这样实在是太难了。在 1962 年,由苏联计算机科学家 G.M.Adelson-Velsky 和 Evgenii Landis 在其论文 An algorithm for the organization of information 中公开了数据结构 AVL (Adelson-Velsky and Landis) 树,这是计算机科学中 最早被发现的 自平衡二叉树。

AVL 的平衡因子

AVL 树将子树的高度限制在差为 1,即一个结点,如果其左子树与由子树的高度差 ∣Dh∣≤1 ,则认为这棵树是平衡的。因此带有平衡因子 -1、 0 或 1 的结点被认为是平衡的,而 -2 或 2 的平衡因子被认为是需要调整的。平衡因子可以直接存储于结点之中,也可以利用存储在结点中的子树高度计算得出。

 简单地计算,一棵 AVL 树的高度最多为 1.44log⁡(N+2)−1.328,实际上的高度只比 log⁡N 稍微多一些。一棵高度为 h 的 AVL 树,其最少结点数 S(h) = S(h - 1) + S(h - 2) + 1 ,S(0)=1, S(1) = 2 。而 AVL 的所有操作均可以在 O(log⁡N) 复杂度下完成。

AVL 的插入操作

在进行插入操作时,和普通的 BST 类似,但是不一样的是需要更新路径上所有结点的平衡信息,并插入完成后有可能破坏 AVL 的特性。如果特性被破坏后,需要恢复平衡才能算插入结束。实际上,总可以通过简单的操作进行修正,这种操作被称为 旋转 (rotation)。

将必须重新平衡的结点叫作 α ,由于任意结点最多有两个孩子,因此高度不平衡时, α 点的两棵子树的高度差 2。这种不平衡可能出现在下面 4 中情况中:

  1. 对 α 的左孩子的左子树进行插入
  2. 对 α 的左孩子的右子树进行插入
  3. 对 α 的右孩子的左子树进行插入
  4. 对 α 的右孩子的右子树进行插入

情况 1 和 4 关于结点 α 镜像对称,情况 2 和 3 关于结点 α 镜像对称。因此从逻辑上来讲,我们只需要考虑两种情况,而编程时需要考虑上面介绍到的所有 4 种情况。

单旋转

情况 1 是插入发生在「外边」的情形,我们称之为 一字形 (zig-zig),可以用 单旋转 (single rotation) 解决。假设结点 n 不满足 AVL 平衡性质,因为其左子树比右子树深 2 层,可以对其进行单旋转修正。修正的过程是:将左子树的根 l 向上移动一层,而将 n 向下移动一层, n 作为 l 的孩子出现在树中。下图展示了插入后出现不平衡的结点 (红色) 、如何旋转、多余子树如何处理以及子树的层数 (蓝字)。

 

对应的情况 4 也是 zig-zig,只需要旋转的方向与操作相镜像即可处理。

双旋转

对于情况 2 、 3 来说,插入在「树内」从而导致 AVL 树无效,这种情况被称为 之字形 (zig-zag),而子树太深通过 single rotation 无法让树平衡,解决这种内部的情形需要 双旋转(double rotation) 解决。

 对应的情况 3 也是 zig-zag,只需要旋转的方向与操作相镜像即可处理。

对 AVL 树插入的总结

可以发现,无论单旋转与双旋转,它都由两个最基本的操作组成:将结点进行左旋 (left rotation) 或右旋 (right rotation),并将多余的一棵子树挂载到下降结点上。

// 左旋
void rotate_left(Node* node) {
  Node* child = node->right;
  node->right = child->left;
  if (child->left != nullptr) {
    child->left->parent = node;
  }
  child->parent = node->parent;
  child->left = node;
  node->parent = child;
  return child;
}
// 右旋
void rotate_right(Node* node) {
  Node* child = node->left;
  node->left = child->right;
  if (child->right != nullptr) {
    child->right->parent = node;
  }
  child->parent = node->parent;
  child->right = node;
  node->parent = child;
  return child;
}

在进行编程时,可以首先定义左右旋这两种基本操作,在根据情况判断如何组合。对于编程细节,远比理论多得多,编写正确的 loop 算法相对于 recursion 并不是一件容易的事,因此更多的会使用 recursion 进行实现。

还有一个重要问题是如何高效的对高度信息进行存储,可以采用平衡因子作为存储而不是一个 int 类型的高度,或者更近一步,利用 2 bit 存储平衡因子 (毕竟只有 3 个状态)。如果你希望将其隐藏到指针中,也是个不错的选择。存储平衡因子将得到些许速度优势,但丧失了简明性,如果你使用隐藏于指针的方法,更加剧的这一问题,不过好消息是你能为此剩下不少内存空间。

AVL 的移除操作

AVL 树的移除与 BST 相当,同样地,移除操作可能会破坏 AVL 特性,因此我们在移除元素后,同样需要对树进行平衡才能算操作完成。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python基于flask搭建http服务(二)—— 实现Excel上传、数据清洗、入库

一、技术点 利用flask 搭建简易的http服务,实现服务端文件上传;利用Blueprint将不同业务拆分至不同文件;利用bootstrap-fileinput组件构建页面;利用flask_cors配置允许跨域请求;利用sqlalchemy实现数据库连接;利用pandas实现Excel读取、清洗、入库;二、具体实现 2.1 目…

基于intel i3/i5/i7 视觉控制器 4个POE GigE

XM-5143 是针对机器视觉行业GigE相机应用场景的一款高性能工业计算机,可使用Intel 6/7代 65W 高性能CPU应对快速检测。4路独立Intel网络芯片,并支持POE供电,可减少布线。并配有快速隔离可编程DI/O芯片. XM-5143的规格产品类型机器视觉控制器防…

分布式事务都有哪些,到底有什么用,在项目当中该用哪个?

分布式的CAP理论应该是人尽皆知了,它描述了一致性(C)、可用性(A)、分区容错性(P)的一系列权衡。很多时候,我们要在一致性和可用性之间权衡,而分布式事务,就是…

20.EC实战 笔记本电脑的休眠唤醒是如何实现的

文章目录 1. EC什么时候(收到什么命令)之后来执行S0-->S3下电时序?2. S3(休眠)状态应该保留哪些电源?3. 控制笔记本进入休眠状态的三种方式总结:前言: 最近很多朋友在咨询休眠唤醒的问题,在笔记本中,休眠唤醒是一个基本功能,如果连休眠唤醒都没有,就失去了笔记本…

Volatile内存语义以及如何正确使用

目录 语义描述 重排序规则 JMM如何实现volatile语义 如何正确使用volatile变量 语义描述 写语义:当写一个volatile变量时候,JMM会把该线程对应的本地内存的共享变量直接刷新到主内存中。 读语义:当读一个volatile变量的时候。JMM会把该线…

分布式锁主动续期的入门级实现-自省 | 简约而不简单

一、背景 如果某个客户端获得锁之后处理时间超过最大约定时间,或者持锁期间内发生了故障导致无法主动释放锁,其持有的锁也能够被其他机制正确释放,并保证后续其它客户端也能加锁,整个处理流程继续正常执行。 简单解释一下&#xf…

LLeetCode题目笔记——6258. 数组中最长的方波

文章目录题目描述题目难度——中等方法一:一次遍历哈希代码Python暴力代码Python一次遍历总结题目描述 这是这周周赛的第二题,本来想是不是双指针的解法,但想半天没想出来咋用双指针,就想到了哈希。 给你一个整数数组 nums 。如果…

PostgreSQL数据库TPCC测试,Banchmarksql 5.0部署详解

1 BenchmarkSQL安装部署 1.1 部署Java环境 首先使用java - version查看是否已有 Java环境(下图是有的情况) 需要注意的是,虚拟机中默认的JDK貌似是不行的哦,请参考下面链接中的博文,教你怎么卸载重装 1.1.1 若没有J…

Python学习基础笔记四十四——模块1

1、看一个例子: 创建一个demo.py文件: print(in demo.py)def hello():print(in hello function) 然后我们在另外一个文件中import这个demo文件: import demo# 调用demo.py文件中的hello()函数 demo.hello() 注意,demo后面没有…

软件安全测试-BurpSuite使用详解

1.BurpSuite简介 Burp Suite 是用于攻击web 应用程序的集成平台,它包含了许多Burp工具,这些不同的burp工具通过协同工作,有效的分享信息,支持以某种工具中的信息为基础供另一种工具使用的方式发起攻击。 它主要用来做安全性渗透测…

我将 9 个 ChatGPT 账号接入微信,我现在整个人都麻了...

大家好,我是米开朗基杨。最近大家都被 ChatGPT 刷屏了,这家伙真是上天入地无所不能,不管什么问题都能解答,而且答案的质量非常高,完全不像机器人。于是乎我冒出个想法:如果把 ChatGPT 接入微信是什么感觉&a…

二维码介绍

二维码介绍 二维码(2-dimensional bar code、二维条码)是用某种特定的几何图形按一定规律在平面(二维方向上)分布的、黑白相间的、记录数据符号信息的图形;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1…

repo的安装和使用

前言 Android 采用 Gerrit 提供代码评审服务,并且开发了一个客户端工具 repo,实现多仓库管理。Git 的开发者对服务端的 Git 源码做了扩展,使得基于 Git(cgit)的代码平台可以很容易引入新的集中式工作流。同样 git-rep…

概率统计·参数估计【矩估计、极大似然估计、无偏性、有效性、相合性】

点估计 设总体的分布函数形式已知,但它的一个或多个参数为未知,借助于总体的一个样本来估计总体未知参数的值的问题称为点估计问题 矩估计 这个还是看例子会比较好理解一些 例 先μ1E(x),μ2E(x2)有几个未知参数就列几次方的期望&#xff…

CSS -- 01. CSS基础

文章目录CSS基础1 CSS简介1.1 HTML的局限性1.2 CSS介绍1.3 CSS语法规范1.4 CSS代码风格2 CSS基础选择器2.1 选择器的分类2.2 标签选择器2.3 **类选择器**2.4 id选择器2.5 通配符选择器2.6 基础选择器总结3 CSS字体属性3.1 字体系列3.2 字体大小3.3 字体粗细3.4 文字样式3.5 字体…

[附源码]JAVA毕业设计医药垃圾分类管理系统(系统+LW)

[附源码]JAVA毕业设计医药垃圾分类管理系统(系统LW) 项目运行 环境项配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目…

Day827.安全性、活跃性以及性能问题 -Java 并发编程实战

安全性、活跃性以及性能问题 Hi,我是阿昌,今天学习记录的是关于安全性、活跃性以及性能问题的内容。 并发编程中需要注意的问题有很多,主要有三个方面,分别是: 安全性问题活跃性问题性能问题 一、安全性问题 相信一…

论文讲解p2p4

本人水平有限,很多地方可能有说错或者理解错的地方请指出,谢谢谅解 一.原始电路图 1.简介:本电路是从1977年一篇电荷重新分配的理念进化而来,论文如下: All-MOS charge redistribution analog-to-digital conversion techniques. --JAMES L. McCREARY 2.因为从一开始充电过…

Java使用H2数据库全方式汇总

H2是轻量级数据库, 可以不需要安装就可以运行,对于快速学习和演示比较适用。关于H2的基本内容可以参考: H2 数据库简介 。 本篇快速介绍H2数据库在各种类型的Java应用中的使用, 包括: Java 项目Java Web 项目Spring B…

《域渗透攻防指南》签名版预售来啦

千呼万唤始出来!终于,在广大粉丝翘首期盼下,国内首本专门讲述域内攻防的书籍《域渗透攻防指南》在2022年最后一个月和大家见面了。为了回馈粉丝的等待,让粉丝早日拿到心仪的书,特此联合机械工业出版社弄了签名版书预售…