深入理解红黑树

小白慎入!本文难度比较高,需要对红黑树有一定的了解再来看!


红黑树

红黑树是一种高级数据结构,是平衡树大家族中的一员,并且听名字就知道这个玩意不是凡物,可能你从未听过,但是你一定会为这样的数据结构感到震撼!它的思路是如此巧妙,让人不得不感叹它是一个艺术品。不仅如此,红黑树依赖它出色稳定的查找、插入、删除特性得到了广泛的运用,是一种经得起实际工业标准作业拷打的数据结构。

文章前提声明

本文不会写任何的代码,因此本文不适合那些纯粹为了CP CODE的读者,或者只是为了了解算法具体步骤的读者,同时本文难度较高,不适合没有背景知识的小白。文章都是我在学习红黑树时候的总结,看完这篇文章你就能够明白红黑树的插入删除原理甚至是设计的思想。丝毫不夸张的说,本文章在理解深度上绝对吊打99%讲红黑树的教程,但是在此之前你必须要学过二叉搜索树(BST)以及B树还有红黑树的一些基础知识。阅读完之后,如果你还想进一步获取具体完整的代码可以选择阅读算法导论或者其他文章。

红黑树与平衡树

先来全面了解红黑树和平衡树。实际上红黑树本来的名字不是红黑树,它的名字叫做对称二叉B树(记住关键词,二叉,B树),后来1978年一篇关于二色框架的论文中用了红黑两种颜色来讨论这种结构的树,后面就沿用了这个名字。那么从原来的名字就可以知道红黑树的思想来源于B树,实际上也可以认为是将一棵B树“二叉化” 并且二叉化的结果拥有和B树相同的优秀特性。那么第一个疑问就是:那为什么要用红黑树不用B树呢?——并不是不可以用,而是实现难度非常高、繁琐,二叉类的平衡树相对于具有不同类型节点的平衡树而言一个显而易见的好处在于每一个节点都具有同样的结构,而B树不行,真正的B树的节点应该是用一个有序链表进行维护的(数据结构套数据结构)。而这也反映了为啥平衡树在概念上很简单但是具体实现却很复杂。因此平衡树的“完美平衡”的定义就很关键,比如AVL树就是任意节点的左右子树高度不超过1,红黑树就是那五条法则(后面会讲)等等,不同的平衡树有着不同的平衡定义,也就导致有些平衡树看起来十分优秀但是没人用(超难实现,二阶AVL等等),而一些看起来比较“弱”的平衡树超多人用(ACM常用的Treap,Splay,为什么说“弱”,是因为这些平衡树的随机性更强,因此严格的算法分析是更加困难甚至无解的,大多数时候说的是操作均摊的期望复杂度)。尽管这些简单的平衡树损失了一些理论上的优势,但是因为放到计算机上的时候仍然要考虑计算优化以及实际的计算机物理限制,因此常数低的代码跑的还不一定比理论更优的慢,而且哪怕真的到了数据规模很大的时候,平衡树的性能也不会有非常明显的差距!(在统计学习有一个“天下没有免费的午餐”的定理,对于不同的数据和不同的操作,谁能保证AVL一定跑不过红黑树,而红黑树一定跑不过AVL,不同的平衡树具有不同特点的操作,比如Splay的区间操作,我对此印象超级深刻,不同的应用场景选择不同的平衡树才是正解!)

好的,为啥我要讲这么多和红黑树操作没有关系的东西呢?因为我想让我的读者知道红黑树为啥叫红黑树,为啥它和B树有关系,以及为啥二叉化?如果你懂了这些,你已经比那种背代码的强太多了——你学会了如何去设计数据结构!学会了如何在理论和实际性能做取舍

红黑树和2-3-4树和2-3树

当初学红黑树的时候,无意之间接触到了两个新词:2-3树和2-3-4树。这两个东西很简单,实际上就是三阶和四阶B树。

下面就构造一下这些树的样子,这里我使用算法可视化的网站来完成,因此结果很可靠:(1,9,2,8,3,7,4,6,5,这个数据BST如果不平衡就是一坨屎)

BST(二叉搜索树):
在这里插入图片描述
2-3树(三阶B树):
在这里插入图片描述
2-3-4树(四阶B树):
在这里插入图片描述
红黑树:
在这里插入图片描述
从上面就可以发现一个重要的事实是B树天生具有平衡的特性,本质在于B树中的每一个节点到达它可以到达的叶子节点的路径长度是相同的(分层)。这个实际很好证明,使用数学归纳的方法就可以了,我这里简单说说:假设当前B树满足这个特性,那么能够增加路径长度的操作必然是节点分裂发生上溢,此时原来的节点变为两个,上溢的节点到所有的叶子节点高度加一,路径长度相同性质仍然满足,表明上溢操作不会影响该性质

在这里插入图片描述
因此如果能够简单地实现这样优秀的数据结构那岂不美哉?哎,红黑树就诞生了,红黑树实际上就是一棵2-3树或者2-3-4树的二叉化形式。然而实际上,基于双色框架,我们可以将这个玩意扩展到m阶B树的二叉化,但由于2-3树和2-3-4树是属于B树中最简单的了,并且恰好避免了一些很麻烦的事情!:)后面会说。所以目前大部分红黑树的代码实现是基于2-3树或者2-3-4树的。

所以红黑树的第一个平衡原则是:红黑树上的任意一个节点到叶子结点的路径上黑色节点的个数相同。(黑色节点个数相当于B树上的距离)

如何二叉化

我们使用红边的形式规定:红边构成的连通块属于一个node。
下面是2-3树中3-node对应的二叉化的节点关系:
在这里插入图片描述
下面是2-3-4树中4-node对应的二叉化的节点关系:
在这里插入图片描述
这里可能会迷惑为啥4-node是左右双边的形式而不是连续的红边形式——主要是设计的时候,我们认为这样更加平衡,论文中没有说为啥这样更好,我的观察是——也就是对于一个4-node,我们最多比较两次就可以得到结果,而如果使用连续的红边,那么最坏情况我们需要走两次次红边也就是比较三次!整体上树的高度是更低的!因此我们认为这样更好,当然也可以不这么做!只不过可能会得到一些很糟糕的结果和更加难实现的代码!因为这样的4-node形式上是不统一的,如果我们允许连续的红边,那么4-node具有三种形式,所以对应的代码操作非常繁琐

所以我们可以得到红黑树的第二条重要的平衡原则(基于2-3-4树等价):从一个节点出发不可能连续多次经过红边。
why not this
为了更加通用以及方便(2-3树的讨论可以看红色的那本《算法》,但是2-3-4树的算法是更加通用的),下面我都是讨论2-3-4树等价的红黑树并且省略NIL节点。

所以现在我们可以上面的那个红黑树转换为下面的2-3-4树形式:

在这里插入图片描述
其中的2,4,8构成了一个4-node,5,6,7构成了一个4-node。

插入操作等价性的讨论1(bottom-up method)

在讨论操作等价性的时候,可以从两方面的逻辑来思考这个操作到底是对的还是错误的:平衡原则和2-3-4树对应操作。首先如果我们从平衡原则来考虑等价,也就说我们的操作能够实时维护这五条性质,也就相当于保证了红黑树的平衡。另一方面,我更加推荐的是从2-3-4树的操作来思考操作的等价性,也就是从设计者的角度出发来理解红黑树的维护操作。具体的例子请接着往下阅读。

上面我们讨论了关于红黑树本质上是2-3-4树的二叉化形式,那么对于2-3-4树的操作,我们又该如何进行等价?实际上这非常巧妙,首先我们明白了一个关键的事实:插入的关键操作在于上溢

那么我们还是从2-3-4树出发来考虑这样一个事实:因为我们每一次找到插入的位置的时候都是想要合并到找到的节点,所以我们规定每一次加入的都是一个红颜色点或者说将插入的点和父亲连接一条红边。那么唯一可能发生上溢的情况就是插入的节点恰好是一个4-node,假设你从未学习过红黑树,你该如何设计这样一个上溢的过程呢?(2-3-4树对应操作角度思考)

在这里插入图片描述
实际上很简单,我们只需要做的就是颜色反转!——将边的颜色修改一下,我们把内部的中间节点弹出去相当于让它和它的父亲合并,然后原本的节点一分为二,所以原来的两条红边变为黑色。操作完之后我们也可以检查有没有违背我们之前说的两条平衡原则(平衡原则角度思考),仔细检查一下就可以知道是没有的,因此该操作是正确的。

然而仅仅有这个操作我们还无法很好地维护其中的第二个平衡原则:不会连续经过两条红色的边。所以我们需要一些操作来维护这个性质(平衡原则角度思考)。

更加深入的理解, 在这里我们很容易发现一个事实,就是对于一个2-3-4树的节点而言,比如4-node,它里面的具体结构是不确定的我们只知道了它有四个孩子和三个键值,但是对于红黑树而言是可以看得到的,那么我想说的是,在红黑树里面它这个节点的结构是一棵简单的平衡BST,说白了我们要维护红边连通的子树是一棵平衡的BST。(这里留下我的一个idea:B树的节点实际上可以认为是一个数据结构,那么它可以是有序链表,为啥就不能是平衡树呢?所以红黑树本质上是把这个数据结构变为了平衡BST融到了原来的B树里面?如果是这样的话,我们可以用这种双色框架实现任意的平衡树结构,将实现复杂的两层的树变为一层,比如说m阶的B树里面的节点对应的是一个高度不超过lgm+1的简单BST,甚至更加大胆,对于具有内部结构的节点的数据结构我们能不能用类似的方法将其扁平化?)

对于一个最多只有三个点的简单平衡BST,那么不平衡的只有四种情况(LL, RR, LR, RL):

在这里插入图片描述
操作完之后我们再去检查一下有没有违背第一条平衡原则,可以发现到达叶子的每一条路径的黑色边数量还是不变的,因此该旋转操作并不会影响第一条平衡原则。

所以整个插入的流程就是向下搜索找到插入的位置,然后不断向上回溯,判断是否会发生上溢,是否需要使用旋转去完成平衡。

插入操作等价性的讨论2(top-down method)

论文里面提出了一个简单的top-down插入算法,它可以做到一次性往下插入而不需要回溯调节平衡。它的思想也很简单,就是在插入之前就已经把路径调节好,这样的话看做是提前的“balance”,到最后面的时候直接插入就可以了

具体的做法可以看看下面的图片:

在这里插入图片描述
可以证明按照这样的插入方法进行插入,到达最后的一个节点时必定不会发生上溢操作。

证明:假设在最后插入的时候发生了溢出,那么最后一个节点必然是属于4-node,由于我们的操作表明在遇到4-node将发生主动分裂,所以该节点不可能是4-node,矛盾。假设不成立。

而其中的平衡调整也是自上而下的,因为可以发现平衡操作只会发生在产生4-node的时候,那么唯二可能的情况就是:上溢导致了父亲节点变为4-node,最后的插入产生了一个4-node。对于第一种情况,由于我们是从上往下调整,所以对于当前分裂的4-node,它只会可能影响到它的父亲,所以对父亲做一次平衡即可。对于第二种情况,我们只需要调整该4-node即可。因此该平衡操作整个流程可以自上而下完成的。

下面展示了使用这个方法插入 1,2,3,4,5

在这里插入图片描述
个人认为插入算法无论是哪个其实都还算是比较好理解的,本质上就是为了维持平衡原则,基于这个出发点就很好理解。

删除操作等价讨论1(bottom-up method)

通常我们认为平衡树的删除操作难度要大于插入。对于2-3-4树来说,我们如果想要使用自底向上的方法去删除,那么最好的选择是操作它的前驱或者后继,这样子的话我们就可以将所有的删除转变为叶子节点的删除。(实际上这对于自上而下的删除方法来说也是更好的选择,因为这样可以避免对左右子树的讨论)

我们先看2-3-4树的删除操作(2-3-4树操作角度思考),然后我们再视图将这样的操作等价到红黑树里面。

(讲个笑话,B树的删除是一场大型的家产继承活动!)

在这里插入图片描述
在这里插入图片描述

可以发现一点是我们删除叶子上面任意一个3-node, 4-node都不会对树的平衡发生任何影响!本质原因就是在于它不会影响树的结构,删了一个9但是7和8仍然是一个node。这时候我们再去删除5,就会发现一个树的结构变了!——4和6中间没有了孩子,这是不合法的,这个时候根据2-3-4树的方法就是——把父亲拉下来,然后检查自己的儿子有没有可以继承家产的,如果有的话就将它拉上来继承家产,如果没有那么就一家团聚

在这里插入图片描述
把父亲6拉下来,发现儿子7或者8可以继承家业,这里选择7,那么7上去,6下来。

在这里插入图片描述

现在我们要继续删除1,
在这里插入图片描述
那么1的父亲2就要下来,但是发现只有一个儿子3,没有儿子能够继承家业,所以一家团聚,2和3合并。

在这里插入图片描述
讨论了2-3-4树的删除之后我们就要想该如何去等价这样的操作呢?首先最显然的一点是如果删除的点属于一个3-node或者4-node,那么就等价于2-3-4树中删除一个3-node,4-node叶子的情况,此时直接删除不用做任何处理。因此最困难的地方在于删除一个叶子是一个2-node的情况,此时要做的就是分类讨论。

同样的我们还是按照2-3-4树等价操作出发,首先看一下兄弟有没有能够继承家产的,如果有的话那么兄弟一定是一个3-node或者4-node。

在这里插入图片描述
基于上面的操作之后我们就可以直接将黄色的点删除掉。深入思考操作的本质,我们只是通过了左旋和右旋来调整父与子之间的关系罢了。因此对应的兄弟如果在右边,那么分别有3种情况:兄弟有一个红色的右儿子(左旋),兄弟有一个红色的左儿子(右旋+左旋),兄弟有两个红色的儿子(任选一个),我们分别做对应的旋转即可!

那么如果兄弟儿子没有能够继承家产的怎么办?这个时候我们将父亲(黑色)拉下来和它的儿子(浅蓝色)进行合并,这个时候就相当于递归的删除了父亲,我们就要处理父亲的位置了,看一下有没有叔叔节点(深蓝色)可以替代父亲的位置,如果有的话,那么叔叔就可以替代父亲的位置继承家产,如果没有那么祖父(棕色)就必须下来和叔叔节点合并!相当于递归向上的过程,直到可以继承家产的人出现!

可以看看下面的操作示意图(删除黄色节点):
在这里插入图片描述
下面不同的角度看这个删除的过程:
在这里插入图片描述
上面的过程中,没删除前的红黑树是部分结构,所以你看到的可能不满足第一条平衡原则(黑色边数相等),但这对我们的删除操作没影响,只要我们保证删除后还是能够和没删除前一样经过相同的黑色边数即可。

仔细思考一下这个过程的本质:无非就是把父亲拉下来和儿子合并然后递归处理删除的父亲这个位置。 在2-3-4树里面这就对应多层的下溢过程,并且操作的过程十分简单,我们合并下溢的操作只需要将父亲到儿子的边标记为红色即可。很多人不理解这个地方,我觉得可能是没有理解这是一个递归的过程和2-3-4树的下溢合并操作。我们刚才讲了红黑树插入的时候是向上溢出,本质上是因为了一个节点满了导致不得不分裂,父亲被分裂开,会继续向上和祖父合并。而删除也是如此,本质就是一个节点个数太少了不得不向下合并,儿子消失了,父亲不得不去替代他,于是祖父会继续向下合并处理父亲的位置。

在这里插入图片描述
这个过程非常抽象,但是我觉得已经讲的很明白了——就是不断的下溢操作,实现也只需要做恰当的颜色反转即可实现!当然,如果是别的文章现在就结束了,但是我明白你看了上面的递归删除可能还是一头雾水,所以我将介绍从自顶向上的角度看待刚才的递归删除!

删除操作等价讨论2(top-down method)

我们假设上面例子中的曾祖父(绿色)是一个红色节点。
那么实际上一开始是这样子的:
在这里插入图片描述
经过上面的递归删除后,我们可以得到:
在这里插入图片描述
其实实际上我们刚才讲过了一个自定向下插入的时候是主动将4-node(因为插入就会上溢的节点)进行分裂上溢,那么删除的时候我们做相反的事情,我们主动将3-node或者4-node拆解进行下溢合并。

在这里插入图片描述
这样子的话我们在最后删除的时候一定可以将该需要删除的点变为红色,所以无须考虑黑色节点的情况。

下面是不同种类的主动向下溢出的过程示例(具体的不同情况可以自己分析一下):

父亲主动分裂下溢:
在这里插入图片描述
兄弟主动分裂下溢:

在这里插入图片描述
可以观察到父亲主动分裂下溢和兄弟主动分裂下溢的过程刚好对应了上面bottom-up method里面的一些方法,比如说父亲主动分裂下溢就相当于父亲下溢合并,而兄弟主动分裂下溢就相当于兄弟节点继承家产。

那么对应于一开始的那个例子,删除黄色节点的过程就会变为这个样子:

在这里插入图片描述
最后的结果是一样的!实际上我们还可以发现一个事实:自顶向下的方法实际上就是把红色边往下push,然后递归的删除方法实际上就是相当于往下pull,一个拉一个推


题外话

一个问题:自己,儿子,父亲,祖父都为黑节点,上面的这种情况真的可能出现吗?问题来源于我在构造数据的过程中,我发现一个这样的情况非常难以构造!如果直接使用正常的插入我断定是不可能产生这样的红黑树的。但是问题是它并没有违反我们定义的红黑树的五个原则。除此之外,这也引发其他的问题:是否对于不违背性质的红黑树我们总能用正常的插入删除构造出来?

下面是我能够构造的最黑的红黑树:(顺序插入1,2,3,4,5,6,7,8,9,10,然后删除10,9,7)

在这里插入图片描述

我几乎找不到自己,父亲,祖父,曾祖父都为黑色并且只有黑色儿子的情况。

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

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

相关文章

华为OD七日集训第6期 十一特辑 - 按算法分类,由易到难,循序渐进,玩转OD

目录 专栏导读华为OD机试算法题太多了,知识点繁杂,如何刷题更有效率呢? 一、逻辑分析二、数据结构1、线性表① 数组② 双指针 2、map与list3、优先队列4、滑动窗口5、二叉树6、并查集7、栈 三、算法1、基础算法① 贪心算法② 二分查找③ 分治…

大咖共探AGI时代机遇,腾讯云助力大模型规模化应用提速

引言 2023 年,科技圈的“顶流”莫过于大模型。自 ChatGPT 的问世拉开大模型与生成式 AI 产业的发展序幕后,国内大模型快速跟进,已完成从技术到产品、再到商业的阶段跨越,并深入垂直行业领域。 新技术的爆发,催生新的应…

mdobus ASCII转CAN OPEN JAE1939协议网关

Modbus RTU协议转换网关是一种常见的设备,用于将Modbus RTU协议转换为其他通信协议。而CANopen是一种基于CAN总线的通信协议,主要用于工业自动化和控制系统中。本文将介绍Modbus RTU协议转换网关如何支持CANopen协议,以及该功能的应用场景和优…

洗地机哪个牌子好用又实惠?口碑最好的洗地机推荐

智能技术飞速发展的时代,扫地机器人这类智能家电其实也在顺应潮流和用户需求,不断更新迭代。暂且不说市面上现有多少个洗地机品牌,单单一个洗地机品牌旗下,其实每年都会有多个系列的新品亮相,我们面对的选择多了&#…

javaee之黑马乐优商城6

商品品牌的查询 上面就是我们需要根据分类id去找品牌 假设我们现在拿到的是 商品的分类id,我们需要根据分类id查询出对应的品牌即可 下面我们拿到上面的接口,直接撸代码 这个是和品牌相关联的操作,因为先去看一下BrandMapper,这个mapper是…

OpenCV显示10bit Raw数据

参考&#xff1a;10 12 14bit图像存储格式&#xff0c;利用Opencv显示10bit Raw数据,并根据鼠标的移动显示对应位置的灰度值。其他bit位数的Raw数据方法类似。 代码实现&#xff1a; #include<opencv2/opencv.hpp> #include<iostream> #include<opencv/highgu…

Qt扩展-QCustomPlot 简介及配置

QCustomPlot 简介及配置 一、概述二、安装教程三、帮助文档的集成 一、概述 QCustomPlot是一个用于绘图和数据可视化的Qt 控件。它没有进一步的依赖关系&#xff0c;并且有良好的文档记录。这个绘图库专注于制作好看的、发布质量的2D绘图、图形和图表&#xff0c;以及为实时可…

中间相遇法(分治类问题非等大分治的平衡做法)

分治&#xff0c;如果分成两半大小不一样&#xff0c;很容易被卡到 O ( n 2 ) O(n^2) O(n2) 在某些题目中&#xff0c;利用中间相遇法&#xff0c;我们可以优化这个过程 其优化的前提是分治的大头在找分界点 复杂度不用证&#xff0c;很好理解吧 这层找地越久&#xff0c;下…

一维卷积神经网络

假设输入数据维度为8&#xff0c;filter维度为5&#xff1b; 不加padding时&#xff0c;输出维度为4&#xff0c;如果filter的数量为16&#xff0c;那么输出数据的shape就是4*16. 一维卷积不代表卷积核只有一维&#xff0c;也不代表被卷积的feature也是一维。一维的意思是说卷…

regexp 应用

今天同事拿出个小栗子 1 如果用like的话 1,22 的情况会被字符串2匹配到这样会有问题 这里需要用concat将uids处理下 比如第一条处理成&#xff0c;1,2&#xff0c;3&#xff0c; 的形式 去模糊匹配 ‘%,1,%’ 当然like这种模糊匹配不太建议使用 2 regexp 用法 单个值 &#x…

MySQL作业1

目录 一.创建一张表&#xff0c;包含以下所有数据类型 建表&#xff1a;​编辑 二.使用以下六种约束 1.非空约束 2.唯一约束 3.主键约束 4.外键约束 5.检查约束 6.默认值约束 一.创建一张表&#xff0c;包含以下所有数据类型 Text 类型&#xff1a; Number 类型&#…

2023-9-26 JZ 复杂链表的复制

题目链接&#xff1a;复杂链表的复制 import java.util.*; /* public class RandomListNode {int label;RandomListNode next null;RandomListNode random null;RandomListNode(int label) {this.label label;} } */ public class Solution {public RandomListNode Clone(Ra…

【ComfyUI】Pytorch预训练模型(torch.hub)缓存地址修改

序言 最近玩ComfyUI时&#xff0c;每次生成图片&#xff0c;总是会下载一些东西&#xff0c;时间长了&#xff0c;C盘就不够用了&#xff0c;今天清理C盘发现&#xff0c;总是会在C:\Users\yutao\.cache\torch\hub\checkpoints这个路径下&#xff0c;下载大模型文件&#xff0…

适合零基础小白学的 Python 教程,视频或者书籍都可以?

Python 有很多衍生方向&#xff0c;比如 web 开发、网络爬虫、数据分析、数据挖掘、机器学习、人工智能等等&#xff0c;就业范围是很广的&#xff0c;Python 相较于别的编程语言对小白入门还是很友好的&#xff0c;Python 入门推荐这份书籍&#xff1a;PYTHON全案例实践 【PD…

6.wifi开发【智能家居:下】,正式开发:智能开关灯,智能采集温湿度,智能调彩灯

一。WEB Server开发 1.需求分析 用户通过页面操作插座彩灯温湿度 【开发前端1】&#xff1a;智能插座网页设计 智能插座网页设计需求 1.通过浏览器访问ESP8266 webserver 2.显示“创客学院-WiFi-智能家居” 3.显示“智能插座” 4.显示当前插座工作状态 5.按键触发插座动作 2.…

新手必看:Android studio 侧边栏实现,带源码

文章目录 前言效果图正文toolbar 用于定义应用程序的导航栏app_bardrawer_layout 用于创建侧边栏导航nav_header_draw app:menu"menu/activity_main_drawer" 前言 本篇内容主要是自己实现侧边栏后的一些总结&#xff0c;部分理论来着网络和ai助手&#xff0c;如有错…

根据文章段落内容自动插入图片php版

每篇内容根据段落判断插入图片代码附上&#xff1a; $chatd"<table>";if(stripos($content,$chatd)0){//随机输出三张图功能if($moduleid!37 &&$thumb){//判断是否存在图$idrand(1,999999);$midrand(1,9999999);$getimg"http://www.nongpin88.co…

uniapp项目实践总结(二十三)网页和小程序应用打包教程

导语&#xff1a;当你的应用程序开发完成后&#xff0c;在发布到互联网之前&#xff0c;需要进行打包操作&#xff0c;包括网页端、小程序端的打包。 目录 准备工作网页打包小程序打包 准备工作 在打包之前&#xff0c;请保证你的 uniapp 应用程序编译到网页、小程序是可以正…

2023国庆后前端面试应该准备什么?

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 表妹一键制作自己的五星红旗国庆头像&#xff0c;超好看 本篇文章会持续更新&#xff0c;也会同步到公众号前端面试官&#xff0c;方便大家随时随地学习…

聊聊并发编程——多线程之synchronized

目录 一.多线程下数据不一致问题 二.锁和synchronized 2.1 并发编程三大特性 2.2引入锁概念 三.synchronized的锁实现原理 3.1 monitorenter和monitorexit 3.2synchronized 锁的升级 3.2.1偏向锁的获取和撤销 3.2.2轻量级锁的加锁和解锁 自适应自旋锁 轻量级锁的解锁…