从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树
参考:自平衡二叉查找树 ,红黑树, 算法:理解红黑树 (英文pdf:红黑树)
目录
- 自平衡二叉树介绍
- avl树
- 2-3树
- LLRBT(Left-leaning red-black tree左倾红黑树 (代码见git)
- 2-3-4树和红黑树
- avl和红黑树的比较
自平衡二叉查找树
诞生的目的:
它是为了解决二叉查找树的查找时间复杂度最差是O(n)的问题而发明的数据结构。
完全二叉树的公式: n = 2h - 1
BST的查找运行时间和BST的高度有关。一个树的高度指的是从树的根开始所能到达的最长的路径长度。
如果按照从小到大的顺序输入一组key值,得到的将是一棵只有右子树的树。见下图。
如这个例子:
有6个节点,它的时间复杂度是O(n)。无论是新增,变更还是查找,删除,都需要诸葛对比key值。
假如要查找节点200,那么节点会比较5次,相当于遍历所有节点了。
这太浪费时间了,因此降低树的高度,就可以减少时间复杂度。
我们知道二叉搜索树的搜索节点的最小时间复杂度是 O(log2n)。因此找到一个高度和节点数量的最佳比例。让它的时间复杂度维持在O(log2n)。
期望是:
如果树中节点的数量为 n,则一棵满足O(log2n) 渐进运行时间的 BST 树的高度应接近于比 log2n 小的最大整数。
但实际问题是:
如何保证 BST 的拓扑结构始终保持树高度与节点数量的最佳比例?
因为 BST 的拓扑结构与节点的插入顺序息息相关,一种方式是通过数据的乱序来保证。所以必须在插入节点前就得到数据。
但是如果无法掌控数据的来源,怎么做?一种方案是新的节点插入不会打乱BST树的平衡。这种始终维持树的平衡状态的数据结构称为:自平衡二叉查找树。self-balancing binary search tree.
一棵平衡树
指的是树能够保持其高度与广度能够保持预先定义的比例。有许多种不同的自平衡 BST 数据结构,例如 AVL 树、红黑树(Red-Black Tree)、2-3 树、2-3-4 树、伸展树(Splay Tree)、B 树等等。
AVL树
1962年, 数学家发明的第一种自平衡二叉查找树,以其名字命名。它的平衡条件是,对每个节点n:
节点n的左子树的高度与右子树的高度差最多是1。即可以没有高度差,也可以高度差距1.
树的高度可递归性定义为:
- 如果节点n没有子节点,则它的高度为 0;
- 如果节点n只有一个子节点,则n的高度为该子节点的高度加 1;
- 如果节点n有两个子节点,则n的高度为两个子节点中高度较高的加 1;
- 如果节点没有子节点,无子节点侧的高度是-1。
例子:
下面有4个BST树,节点中的数代表节点的值,左右两侧的数代表左右子树的高度。a, b是AVL树,c,d不是,因为c/d不满足AVL的平衡条件。
当创建一棵 AVL 树时,难点在于如何保证 AVL 的平衡性质要求,而不用关注对树的具体操作。也就是说,无论是向树添加节点还是删除节点,最重要的事情就是保持树的平衡。
AVL 树通过 "旋转操作(rotations)" 来保持树的平衡。旋转操作可以重塑树的拓扑结构来恢复树的平衡,更重要的是,重塑后的树依然符合二叉查找树的性质要求。
当向一棵 AVL 树中插入一个新的节点时,需要经过两阶段的过程。
- 插入新节点的操作将使用与向 BST 树中插入新节点时使用的相同的查找算法。新的节点将做为一个叶子节点被添加到树中合适的位置,以满足 BST 的性质要求。在添加完节点后,将导致树的结构可能已经违背 AVL 树的性质要求。
- 在第二个阶段中,将遍历访问路径,来检查每个节点左右子树高度。如果存在某节点的左右子树的高度差大于 1 时,则需要使用旋转操作来处理。
例子:
有时除了像上图中描述的简单的旋转操作之外,可能还需要进行多次旋转操作。最重要的就是要意识到插入操作和删除操作都会破坏 AVL 树的平衡,而旋转操作就是解决这些问题的法宝。
通过确保所有节点的左右子树的差小于等于 1,AVL 树保证了插入、删除和查找操作将始终保持 O(log2n) 的渐进运行时间,而与插入或删除节点的顺序无关。
2-3树
2-3树是多叉树,它同样是一个平衡查找树。
二叉树中,每个节点最多只储存一个数据项的同时,最多也只有左右两条链接。而2-3树则不同:
定义
2-3树是一个多叉树。一个节点可以保存1个或2个数据项。可以有0-3个子节点。
- 有一个数据项的节点必须有2个子节点。
- 有二个数据项的节点必须有3个子节点。
- 每个节点的数据项按照,数据项的key,从左到右保持从小到大的顺序。
- 两个key之间的子树的key的值,大于父节点左key,小于父节点的右key.
- 作为平衡树,所有从leaf到root的path的高度相同,因此所有的叶子节点都是位于同一层。
- ⚠️2-3树的节点分裂是:自底向上的(不能预分裂),而且2-3树节点分裂必须用到新数据项。
- 由1,2可知,除了叶节点不允许出现空节点。
时间复杂度:
- 在最坏的情况下,也就是所有的节点都是2-node节点,查找效率为lgN
- 在最好的情况下,所有的节点都是3-node节点,查找效率为log3N约等于0.631lgN
原理:
2-3树在插入key值的过程中会不断构建并分解3-key节点来保持树的平衡,因此在2-3树就可以避免二叉树的不平衡导致的效率低下的问题。
2-3树是自平衡的树,例如插入一组从小到大的key值的元素:
- 首先2-3树已经构建一个根节点
- 然后插入值为1的key。(⚠️2-3树允许一个节点储存两个key值)
- 插入2。成为了临时的3key节点,这是2-3树不允许的,需要分裂,并把1上传,形成二叉树结构。
- 插入3。⚠️这时的2-3树是左右平衡的。
- 再插入4。形成了3-key节点,需要分解它,并导致树的不平衡。(⚠️定义所有叶节点都在同一层)
- 重构,把节点3和节点1合并。成为一个2-3树。
- 再插入5。然后插入6,形成一个3key节点。分解它,上传5节点。根节点形成3-key节点,树虽然平衡,但不符合2-3树的定义:每个节点最多有2个数据key。
- 分解root节点:最后的树是左右平衡的。
由此可知,2-3树可以避免二叉搜索树的不平衡导致的效率低下的问题。
总结-插入方法:
- 如果2-3树已存在当前插入的key,则插入失败,正确的插入一定是在叶子节点内插入。
- 如果等待插入的节点内只有一个节点,则直接插入。
- 如果等待插入的节点内有2个节点,插入后,需要对节点分裂。形成一个二叉树结构,然后将父节点再向上传递。
- 重复2和3的步骤,直到满足2-3树的定义。
删除方法:
比较复杂,未细看。参考:https://blog.csdn.net/u012152619/article/details/84332165
首先找到所在要删除的关键字(假设是K)所在的节点。
如果这个节点不是叶节点,就要找到中序排列时K后面的关键字所在的节点,这个节点一定是叶节点(因为它在右子树中是最小的)。然后交换这两个节点,那么所删除的关键字最终还是在一个叶节点中。
如果这个节点是叶节点,分叶节点和非叶节点,再根据key的数量分为4种:
- 1key的叶节点
- 2key的叶节点
- 1key的非叶节点
- 2key的非叶节点
下面从简单到复杂情况分析:
1. 如果删除的节点是2key的叶节点,只需删除目标key即可。2key叶节点变为1key叶节点,仍是2-3树。
10 10
/ \ => / \
4,6 18 4,x 18
2. 如果删除的节点属于2key非叶节点,则中序遍历找到待删除节点的后继节点,然后将后继节点和待删除节点位置交换。 此时问题转化为删除节点为叶子节点了。这时有2种情况:
- 待删除节点位于一个2-key叶节点内。删除方法见方法1。
10, 20 12,20
/ | \ => / | \
4 12, 15 25 4 x ,15 25
#直接删除10即可。
- 待删除节点是一个独立的叶子节点。 删除方法见
从二叉查找树到平衡树:avl, 2-3树,左倾红黑树(含实现代码),传统红黑树的更多相关文章
- 二叉查找树、平衡二叉树(AVL)、B+树、联合索引
1. [定义] 二叉排序树(二拆查找树)中,左子树都比节点小,右子树都比节点大,递归定义. [性能] 二叉排序树的性能取决于二叉树的层数 最好的情况是 O(logn),存在于完全二叉排序树情况下,其访 ...
- 有了二叉查找树、平衡树(AVL)为啥还需要红黑树?
序言 二叉查找树的缺点 平衡二叉树 虽然平衡树解决了二叉查找树退化为近似链表的缺点,能够把查找时间控制在 O(logn),不过却不是最佳的,因为平衡树要求每个节点的左子树和右子树的高度差至多等于1,这 ...
- Algorithms: 二叉平衡树(AVL)
二叉平衡树(AVL): 这个数据结构我在三月份学数据结构结构的时候遇到过.但当时没调通.也就没写下来.前几天要用的时候给调好了!详细AVL是什么,我就不介绍了,维基百科都有. 后面两月又要忙了. ...
- 平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】
平衡树初阶——AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是 ...
- (4) 二叉平衡树, AVL树
1.为什么要有平衡二叉树? 上一节我们讲了一般的二叉查找树, 其期望深度为O(log2n), 其各操作的时间复杂度O(log2n)同时也是由此决定的.但是在某些情况下(如在插入的序列是有序的时候), ...
- 树-二叉平衡树AVL
基本概念 AVL树:树中任何节点的两个子树的高度最大差别为1. AVL树的查找.插入和删除在平均和最坏情况下都是O(logn). AVL实现 AVL树的节点包括的几个组成对象: (01) key -- ...
- AVL排序二叉树树
AVL树第一部分,(插入) AVL树是一种自平衡二叉搜索树(BST),其中对于所有节点,左右子树的高度差不能超过1. 一个AVL树的示例 上面的树是AVL树,因为每个节点的左子树和右子树的高度之间的差 ...
- 二叉平衡树AVL的插入与删除(java实现)
二叉平衡树 全图基础解释参考链接:http://btechsmartclass.com/data_structures/avl-trees.html 二叉平衡树:https://www.cnblogs ...
- 【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)
http://www.lydsy.com/JudgeOnline/problem.php?id=1146 第一种做法(时间太感人): 第二种做法(rank5,好开心) ================ ...
随机推荐
- Spark Streaming的实时词频和累加词频统计
(注:运行环境是Ubuntu16, pycharm) 1. 按时段统计:获取scoket端口传输的数据(英文数据即可,方便分词),统计各个时间段内每个单词出现的次数(每个时间段都分别统计,需要使用的关 ...
- iView中Tree组件children中动态checked选中后取消勾选再选中无效问题
如题,我有一个Tree组件,动态更新check选中子级列表的时候,取消勾选了再点击选中时复选框样式不是勾选状态,但是数据已经有了. 对此解决方案是:将初始化时Tree组件data数据深拷贝一遍再去判断 ...
- spark-初阶①(介绍+RDD)
spark-初阶①(介绍+RDD) Spark是什么? Apache Spark 是一个快速的, 多用途的集群计算系统, 相对于 Hadoop MapReduce 将中间结果保存在磁盘中, Spark ...
- HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并)
layout: post title: HDU-6704 K-th occurrence (后缀自动机father树上倍增建权值线段树合并) author: "luowentaoaa&quo ...
- HTML 标签的 for 属性
HTML 标签的 for 属性 for 属性规定 label 与哪个表单元素绑定. 隐式和显式的联系 label通常以下面两种方式中的一种来和表单控件相联系: 将表单控件作为标记标签的内容,这样的就是 ...
- 安装 pybloomfilter
1.在windows的cmd下,使用 pip install pybloomfiltermmap 命令安装,pybloomfiltermmap 时报错 ,错误信息如下 根据错误信息分析,报错原因是需要 ...
- ubuntu 系统升级
1.更新软件源和软件 $ sudo apt-get update && sudo apt-get dist-upgrade 2.安装update-manager-core $ sudo ...
- Vasya and Endless Credits CodeForces - 1107F (二分图完美匹配)
大意: n中贷款, 每种只能买一次, 第$i$种给$a_i$元, 要还款$k_i$个月, 每个月底还$b_i$元. 每个月可以在月初申请一种贷. 求某一时刻能得到的最大钱数.
- 啥叫K8s?啥是k8s?
•Kubernetes介绍 1.背景介绍 云计算飞速发展 - IaaS - PaaS - SaaS Docker技术突飞猛进 - 一次构建,到处运行 - 容器的快速轻量 - 完整的生态环境 2.什么是 ...
- C#面向对象20 序列化和反序列化
序列化和反序列化 序列化是把一个内存中的对象的信息转化成一个可以持久化保存的形式,以便于保存或传输,序列化的主要作用是不同平台之间进行通信,常用的有序列化有json.xml.文件等 一.序列化为j ...
- 二叉查找树、平衡二叉树(AVL)、B+树、联合索引