图文并茂丨深入理解红黑树 一、红黑树的底层逻辑 大家都听说过红黑树,也都知道红黑树很厉害,是计算机里面评价非常高的数据结构。但是每当想学习红黑树的时候,却总是找不到通俗易懂很好理解的学习资料。很多书上上来就是红黑树的定义,然后就是红黑树的实现,直接就把人给整晕了。光看红黑树的定义就有5条,为什么要有5条定义,为什么要这么定义,这么定义是什么意思,光定义都让人懵了,更别说实现了。我看最近抖音上有很多人在讲底层逻辑,只要你掌握了底层逻辑,其它的问题都不在话下,今天我们也来讲一讲红黑树的底层逻辑。在讲之前我们先介绍一下红黑树的诞生,红黑树是Rudolf Bayer在1972年首先提出来的,不过当时并不叫红黑树,而是叫对称二叉 B 树(symmetric binary B-trees)。后来在1978年Leo J. Guibas 和 Robert Sedgewick 对此数据结构进行了修改和完善,并重新命名为红黑树。为什么叫红黑树呢?有两种说法,因为红黑树中要对节点连接做两种颜色的区分,一说是因为当时的书写笔只有红色和黑色两种颜色,另一说是当时的打印机只有红和黑两种颜色。 1.1 红黑树的本质 什么是红黑树,红黑树的本质是什么?一句话就可以说清楚,红黑树是二叉树的身体、2-3 B树的灵魂,用计算机的语言来说就是,红黑树是二叉树的存储结构、2-3 B树的操作逻辑。那么红黑树为什么是这样的呢?这就和遗传学中的道理是一样的了,是为了取得杂交优势,既继承父本的优势又继承母本的优势,同时又抛弃了父本和母本的劣势。我们把二叉树看成是母本,2-3 B树看成是父本,母本的优势就是存储结构简单,还有比二叉树更简单的树形结构吗,没有了。父本的优势就是B树是绝对平衡树,任何时候都是绝对平衡的。但是父本的劣势也是因于此,为了实现绝对平衡,B树的存储结构比较复杂,当然操作逻辑也比较复杂。而二叉树虽然存储结构简单,操作也简单,但是它最大的缺点就是不一定平衡,一棵树如果不平衡,它的操作复杂度就会从O(logn)退化为O(n),这是一个很严重的问题。为了实现一个既平衡又相对简单的树形结构,于是有人就想到了把二叉树和2-3 B树给结合起来,取二叉树的存储结构和2-3 B树的操作逻辑,用二叉树来模拟2-3 B树,于是红黑树就诞生了,这样红黑树就既实现了存储结构简单又实现了平衡的效果。红黑树的定义也就比较好理解了,就是为了保证红黑树在逻辑上是一颗2-3 B 树。我们这里暂时先不讲红黑树的定义,我们先来讲一讲2-3 B树,当你把B树的逻辑理解透了,那么掌握红黑树的定义和实现就易如反掌。这里说的二叉树具体来说是二叉搜索树,下文也会简单地讲一下。 1.2 B树简介 树形结构首先可以分为等叉树和不等叉树,等叉树是每个节点的键值个数都相同、子节点个数也都相同,不等叉树是每个节点的键值个数不一定相同、子节点个数也不一定相同。 最简单的等叉树是二叉树,直接二叉树的作用并不大,我们一般会要求二叉树所有的节点按照一定的顺序排列,这样我们进行插入、删除、查找时效率就会非常高,我们把这样的树叫做二叉搜索树或者二叉查找树。它的具体定义是这样的,二叉搜索树,要么是个空树,要么符合以下几个条件,1.左子树如果存在的话,左子树所有节点的键值都要小于根节点的键值,2.右子树如果存在的话,右子树所有节点的键值都要大于根节点的键值,3.它的所有子树也都要符合前面的两个条件(前面的小于同时换成大于也成立)。经过这样定义之后,二叉树就变成了二叉搜索树,它的插入、删除、查找效率一般情况下都是O(logn)。等叉树还有三叉树、四叉树、五叉树等,但是它们和二叉树相比,除了更复杂以外,好像也没有啥优点,所以很少听到有人用过。 不等叉树和等叉树相比除了更省空间以外,好像也没啥特别的用处,但是如果我们对不等叉树的节点键值数和插入、删除逻辑添加一些特殊的要求,使其能达到绝对平衡的效果,我们就把这种树叫做B树。B树全称Balance Tree,是一种自平衡树。它和等叉树最大的不同首先表现在存储结构上,等叉树上每个节点的键值数和分叉数都是相同的,而B树则不是。如果某个B树上所有节点的分叉数最大值是m,则把这个B数叫做m阶B树。下面我们来看一下B树的具体定义:所有节点最多有m个子节点。非根非叶子节点至少有m/2(向上取整)个子节点。根节点至少有两个子节点(除非总结点数都不够3个)。所有叶子节点都在同一层。任意节点如果有k个键值,则有k+1个子节点指针,键值要按照从小到大排列,子节点树上所有的键值都要在对应的两个键值之间。 B树的定义好像很复杂,但是仔细分析一下也不复杂,可以分为3类。一是对子节点的个数进行限制,包括1、2、3三条,1是限制最大子节点数的,这也是m阶B树的m的由来,2是限制非根非叶子节点的子节点数,叶子节点的子节点数是0,所以才叫叶子,没啥限制的,根比较特殊,下一条说,普通节点的子节点数至少要是m/2(向上取整)个,这么要求是为了提高树的紧凑性,避免树变得过于瘦高,3是限制根节点的子节点个数,要求根节点至少有2个子节点。二是要求整个树是要有序的,是5,第5条虽然不好用语言描述,但是它的意思是很简单明确的,就是键值要从小到大排序,键值之间的子节点的值也要在两个键值之间,如果是两端的,则要小于最小键值,或者大于最大键值。三是对树高的要求,是4,第4条说的是所有叶子都在同一层,也就是说每一个叶子的深度都是相同的,这也是整个树的高度,这一条直接规定了B树是一个绝对平衡树,不会出现退化成线性结构的可能,所以B树的效率一直是O(logn)的,没有例外情况。 B树的5条定义,其它的都好实现,就第4条比较难,而它也是B树保持绝对平衡的关键。那么第4条如何实现呢?这就要对它的插入和删除做特殊规定了。插入的时候只能在叶子节点进行插入,如果插入后叶子节点满了,则会对这个叶子节点进行分裂操作,选取中间键值把这个叶子一分为三,小于这个键值的重新组成一个节点,大于这个键值的重新组成一个节点,然后把这个中间键值送给父节点。如果父节点没有满,则插入操作结束。如果父节点也满了,则递归此操作,直至根节点。如果根节点也满了,则对根节点进行分裂,生成新的根节点,这时树的高度就会增加1,由于是在根部增长,所以所有节点的高度都增加了,整个树还是平衡的。总结起来,B树插入的特点就是底部插入、根部增长,而二叉树是底部插入、底部增长,时间长了容易生长不平衡,B树则没有这种烦恼,它一直都是平衡的。虽然B树的插入一直是平衡的,但是如果删除操作是直接执行的,也会导致B树被删的不平衡了,所以B树的删除也要特殊操作才行。B树的删除更加复杂,我们首先考虑如果被删除的键值不在叶子节点上,我们找到它的后继,它的后继一定是在叶子节点上,然后用后继覆盖它,再去删除这个后继,然后就是叶子节点的删除了。如果叶子节点里面的键值个数足够,删除一个也满足B树要求的个数,则直接删除,没有问题。如果自己的键值数不够了,则要考虑向临近的兄弟节点借,借的时候要经过父节点转手一次,并不是直接借人家的节点值,而是兄弟节点给父节点一个合适的键值,父节点再拿一个合适的键值给自己。如果兄弟节点也没有多余的键值可以借了,那就要向父节点借一个素并和兄弟节点进行合并处理,自己和左兄弟节点或者右兄弟节点再加上父节点的一个键值,合并成一个新的节点。如果父节点被借走了一个键值之后,键值数也小于要求了,则继续此过程,直至最后向根节点借,如果根节点也被借没了,则新合并的节点成为根节点,B树的高度减1。 我们对B树有了基本的了解,对B树的插入删除操作也有了大概的认识,但是可能还不是很清晰,下一章我们以2-3 B树为例,详细地讲一讲B树的操作逻辑。 视频讲解 通俗易懂的红黑树,B树,B+树 本质区别及应用场景(上) 通俗易懂的红黑树,B树,B+树 本质区别及应用场景(下) LinuxC++后台服务器开发架构师免费学习地址 【文章福利】:小编整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!~加入(需要自取)



















2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/24492.html





























