当前位置: 首页 > article >正文

【Python 数据结构 9.树】

我装作漠视一切,其实我在乎的太多,但我知道抓得越紧越容易失去

                                                                                                        —— 25.3.6

一、树的基本概念

1.树的定义

        树是n个结点的有限集合,n=0时为空树。当n大于0的时候,满足如下两个条件:

        ① 有且仅有一个特定的结点,称为根结点 Root

        ② 当 n > 1 时,其余结点分为 m 个互不相交的有限集合,T1、T2、T3、….Tm,其中每个 Ti 又是一棵树,并且为 Root 的子树


2.子树的定义

        树的定义用到了递归的思想。即树的定义中,还用到了树的概念。

        T1 和 T2 就是 a 的子树,结点 d、9、h、i 组成的树又是结点 b 的子树

        子树的个数没有限制,但是它们一定是互不相交


3.结点的定义

        树的结点包含一个数据域 和 m 个指针域,指针域用来指向它的子树。结点的分类为:根结点、叶子结点、内部结点。结点拥有子树的个数,被称为结点的度,树中各个结点度的最大值,被称为 树的度

1) 根结点

一棵树的根结点只有一个

2) 叶子结点

        度为 0 的结点被称为叶子结点,叶子结点不能指向任何子树

3) 内部结点

        除了根结点和叶子结点以外的结点,都被称为内部结点


4.结点的关系

1) 孩子结点

        对于某个结点,它的子树的根结点被称为该结点的孩子结点

2) 父节点

        该结点被称为孩子结点的父结点

3) 兄弟结点

        同一父结点下的孩子结点互相称为兄弟结点


5.树的深度

        结点的层次,从根结点开始记为第 1 层,如果某个结点在第 i 层,则它的子树的根结点在第 i+1 层。树中结点的最大层次称为树的深度,如图所示,是一棵深度为 4  的树。


6.森林的定义

        森林是 m 棵互不相交的树的集合。对于树的每个结点而言,其子树集合就是森林,如图所示,b 和 c 两棵子树组成的集合就是一个森林。


二、树的数据结构表示

1.结点 id

        为了方便树数据的读取和修改,我们一般用一个数字来代表树的结点,这个数字就是树的结点 id,它是一个唯一 id,每个树结点的结点 id 都是不同的。如图所示,每个结点都有一个 id 作为标识。


2.结点池

        在处理树相关的问题时,结点一定是有限的,有时候也一定是确定的,比如一个问题给出的时候,给出一个 n 个结点的树,这个 n 必然是有上限的,所以我们可以事先将所有的结点存储在一个顺序表中,然后通过 结点id 索引的方式,快速获取到对应的结点。而这个顺序表就是结点池。所以,根据结点 id 获取结点的这步操作,时间复杂度是 O(1)的。


3.结点数据

        树的结点数据可以是任意的,这样就可以处理任何情况下的问题,如图所示,树结点的数据的类型是字符类型(a、b、c、d、e、f、g、h、i)。


4.孩子结点列表

        每个结点都要保存一个孩子结点列表(叶子结点的孩子结点列表是空的),注意这里所说的是列表,不是顺序表也不是链表,当然也不是特指 Python 中的 list,而指的就是自然语义上的列表,我们可以用顺序表来实现对孩子结点的存储,也可以用链表来实现对孩子结点的存储。


5.添加树边

        如图所示,两个绿色的箭头,分别代表的就是添加两条边的过程。添加树边(a -> b、a -> c )的过程,可以通过树的结点 id 先获取到实际的树结点,然后将孩子结点添加到父结点的孩子结点列表来完成。


6.树的遍历

        树的遍历的引入,让我们开始了解递归的概念,而树本身也是一种递归的数据结构


三、Python中的树

        用Python实现下图的树,并用深度遍历的方式将其打印出来

代码实现

Ⅰ、树的结点类定义

树节点的基本结构:树是一种分层数据结构,每个节点可以有零个或多个子节点。TreeNode 类通过 val 属性存储节点的值,并通过 childrenList 属性维护子节点的列表。

动态添加子节点addChild 方法允许在树结构中动态添加子节点,使得树可以根据需要扩展。

通用性val 属性初始为 None,使得节点可以存储任意类型的值(如整数、字符串、对象等),增加了代码的通用性。

append():Python 中列表(list)对象的一个内置方法,用于在列表的末尾添加一个元素。该方法会直接修改原列表,而不是返回一个新的列表。

参数类型作用
object任意类型要添加到列表末尾的元素。可以是数字、字符串、列表、字典等任何 Python 对象。
class TreeNode:def __init__(self):self.val = Noneself.childrenList = []def addChild(self, node):self.childrenList.append(node)

Ⅱ、树结构初始化

列表推导式:用于从一个可迭代对象(如列表、元组、字符串等)中快速生成一个新的列表。它可以将复杂的循环和条件判断合并为一行代码,使代码更加简洁和高效。

参数作用
expressionitem执行的操作或表达式,生成新列表中的元素。
itemiterable中遍历的每一个元素。
iterable可迭代对象(如列表、元组、字符串等)。
condition可选的条件语句,用于筛选要包含在新列表中的元素。

range():用于生成一个不可变的数字序列,通常用于循环控制或生成数字列表。它可以根据指定的起始值、结束值和步长生成一系列数字。

参数作用
start序列的起始值(包含),默认为0。
stop序列的结束值(不包含)。
step步长,默认为1。如果为负数,则生成递减的序列。
class Tree:def __init__(self, maxNodes):self.root = Noneself.nodes = [TreeNode() for i in range(maxNodes)]

Ⅲ、根据索引获取树节点

        根据给定的索引 index,从 self.nodes 列表中获取对应的树节点

    def getTreeNode(self, index):return self.nodes[index]

Ⅳ、设置根结点

        调用 getTreeNode(rootIndex) 获取索引为 rootIndex 的节点,并将其赋值给 self.root,从而将该节点设置为树的根节点。

    def setRoot(self, rootIndex):self.root = self.getTreeNode(rootIndex)

Ⅴ、添加孩子结点

        首先通过 getTreeNode(parentIndex) 获取父节点,然后通过 getTreeNode(childIndex) 获取子节点,最后调用父节点的 addChild 方法将子节点添加到父节点的子节点列表中

    def addChild(self, parentIndex, childIndex):parent = self.getTreeNode(parentIndex)child = self.getTreeNode(childIndex)parent.addChild(child)

Ⅵ、 给指定索引结点赋值

        通过 getTreeNode(index) 获取索引为 index 的节点,并将其 val 属性设置为 val

    def AssignData(self, index, val):self.getTreeNode(index).val = val

Ⅶ、打印树结构

        如果 node 为 None,则从根节点 self.root 开始打印。首先打印当前节点的值 node.val,然后递归地遍历并打印每个子节点的值。node.childrenList 是当前节点的子节点列表

    def PrintTree(self,node = None):if node is None:node = self.rootprint(node.val,end=" ")for child in node.childrenList:self.PrintTree(child)

Ⅷ、 Python中树的实现

class TreeNode:def __init__(self):self.val = Noneself.childrenList = []def addChild(self, node):self.childrenList.append(node)class Tree:def __init__(self, maxNodes):self.root = Noneself.nodes = [TreeNode() for i in range(maxNodes)]def getTreeNode(self, index):return self.nodes[index]def setRoot(self, rootIndex):self.root = self.getTreeNode(rootIndex)def addChild(self, parentIndex, childIndex):parent = self.getTreeNode(parentIndex)child = self.getTreeNode(childIndex)parent.addChild(child)def AssignData(self, index, val):self.getTreeNode(index).val = valdef PrintTree(self,node = None):if node is None:node = self.rootprint(node.val,end=" ")for child in node.childrenList:self.PrintTree(child)def test():T = Tree(9)T.setRoot(0)T.AssignData(0,'a')T.AssignData(1,'b')T.AssignData(2,'c')T.AssignData(3,'d')T.AssignData(4,'e')T.AssignData(5,'f')T.AssignData(6,'g')T.AssignData(7,'h')T.AssignData(8,'i')T.addChild(0,1)T.addChild(0,2)T.addChild(1,3)T.addChild(2,4)T.addChild(2,5)T.addChild(3,6)T.addChild(3,7)T.addChild(3,8)T.PrintTree()test()


四、实战

1.2236. 判断根结点是否等于子结点之和

给你一个 二叉树 的根结点 root,该二叉树由恰好 3 个结点组成:根结点、左子结点和右子结点。

如果根结点值等于两个子结点值之和,返回 true ,否则返回 false 。

示例 1:

输入:root = [10,4,6]
输出:true
解释:根结点、左子结点和右子结点的值分别是 10 、4 和 6 。
由于 10 等于 4 + 6 ,因此返回 true 。

示例 2:

输入:root = [5,3,1]
输出:false
解释:根结点、左子结点和右子结点的值分别是 5 、3 和 1 。
由于 5 不等于 3 + 1 ,因此返回 false 。

提示:

  • 树只包含根结点、左子结点和右子结点
  • -100 <= Node.val <= 100

方法一、直接判断是否相等

思路与算法

核心逻辑:直接比较根节点的值 root.val 与其左右子节点值之和 root.left.val + root.right.val,若相等则返回 True,否则返回 False

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def checkTree(self, root: Optional[TreeNode]) -> bool:if root == None:return Falsereturn root.val == root.left.val + root.right.val


2.104. 二叉树的最大深度

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:3

示例 2:

输入:root = [1,null,2]
输出:2

提示:

  • 树中节点的数量在 [0, 104] 区间内。
  • -100 <= Node.val <= 100

方法一 递归 

思路与算法

递归终止条件如果当前节点 root 为 None,表示已经遍历到了叶子节点的下一层,返回深度 0。​

递归计算左右子树的深度分别递归计算左子树和右子树的最大深度,分别存储在 left 和 right 中。

返回当前树的最大深度当前树的最大深度为左右子树深度的较大值加 1(加 1 表示当前层)。

max(): 返回一组数值中的最大值。它可以用于多种编程语言和工具中,如Python、Excel、MATLAB等。

参数作用
number1number2, ...必需,表示要比较的数值或数值范围。在Excel中,最多可包含255个参数

4

iterable在Python中,表示可迭代对象(如列表、元组等),函数将返回该对象中的最大值

5

key在Python中,可选参数,用于指定一个函数作为比较的标准。例如,可以使用key=lambda x: abs(x)来比较绝对值

5

default在Python中,可选参数,当可迭代对象为空时,返回此默认值

5

dim在MATLAB中,可选参数,用于指定在矩阵的哪一维上查找最大值

1

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def maxDepth(self, root: Optional[TreeNode]) -> int:if root == None:return 0left = self.maxDepth(root.left)right = self.maxDepth(root.right)return max(left, right) + 1


方法二、先序遍历 + 递归

思路与算法

dfs 方法:这是一个递归方法,用于遍历二叉树的每个节点。

参数 root 是当前节点,depth 是当前节点的深度。

如果当前深度 depth 大于 self.max,则更新 self.max 为当前深度。

如果当前节点 root 不为空,则递归调用 dfs 方法遍历其左子树和右子树,并将深度 depth 加 1。

calculateDepth 方法:这是主方法,用于计算二叉树的最大深度。

首先初始化 self.max 为 0,表示当前最大深度。然后调用 dfs 方法,从根节点开始遍历,初始深度为 0。最后返回 self.max,即二叉树的最大深度。 

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def dfs(self, root:Optional[TreeNode], depth:int) -> None:if depth > self.max:self.max = depthif root:self.dfs(root.left, depth + 1)self.dfs(root.right, depth + 1)def calculateDepth(self, root: Optional[TreeNode]) -> int:self.max = 0self.dfs(root, 0)return self.max


五、树的应用

        在信息量非常大的情况下,需要快速将信息分类,就可以用到树这种数据结构

相关文章:

【Python 数据结构 9.树】

我装作漠视一切&#xff0c;其实我在乎的太多&#xff0c;但我知道抓得越紧越容易失去 —— 25.3.6 一、树的基本概念 1.树的定义 树是n个结点的有限集合&#xff0c;n0时为空树。当n大于0的时候&#xff0c;满足如下两个条件&#xff1a; ① 有且仅有一个特定的结点&#xff…...

LLM 学习(二 完结 Multi-Head Attention、Encoder、Decoder)

文章目录 LLM 学习&#xff08;二 完结 Multi-Head Attention、Encoder、Decoder&#xff09;Self-Attention &#xff08;自注意力机制&#xff09;结构多头注意力 EncoderAdd & Norm 层Feed Forward 层 EncoderDecoder的第一个Multi-Head AttentionMasked 操作Teacher Fo…...

计算机网络软考

1.物理层 1.两个主机之间发送数据的过程 自上而下的封装数据&#xff0c;自下而上的解封装数据&#xff0c;实现数据的传输 2.数据、信号、码元 码元就是数字通信里用来表示信息的基本信号单元。比如在二进制中&#xff0c;用高电平代表 “1”、低电平代表 “0”&#xff0c…...

从高资源到低资源语言的全覆盖:Manus AI的数据革命与迁移学习策略

在全球化语境下,多语言手写识别的最大挑战并非技术本身的复杂性,而是语言资源的极度不均衡——英语、中文等高资源语言拥有海量标注数据,而藏语、斯瓦希里语等低资源语言往往仅有零星样本。Manus AI通过数据生态构建与知识迁移技术,打破了这一资源垄断,实现了从高资源到低…...

《白帽子讲 Web 安全》之身份认证

目录 引言 一、概述 二、密码安全性 三、认证方式 &#xff08;一&#xff09;HTTP 认证 &#xff08;二&#xff09;表单登录 &#xff08;三&#xff09;客户端证书 &#xff08;四&#xff09;一次性密码&#xff08;OTP&#xff09; &#xff08;五&#xff09;多因…...

VBA 数据库同一表的当前行与其他行的主键重复判断实现方案

目的&#xff0c;判断是否主键重复&#xff0c;不重复则登录新数据&#xff0c;重复则不登录。 定义类型&#xff1a; DataRecord   tableName 表名   rowNumber 行号   columnName 列名   data 数据 想要实现的代码逻辑如下&#xff1a; 模拟数据库的登录过程。假设…...

FreeRTOS第17篇:FreeRTOS链表实现细节05_MiniListItem_t:FreeRTOS内存优化

文/指尖动听知识库-星愿 文章为付费内容,商业行为,禁止私自转载及抄袭,违者必究!!! 文章专栏:深入FreeRTOS内核:从原理到实战的嵌入式开发指南 1 为什么需要迷你列表项? 在嵌入式系统中,内存资源极其宝贵。FreeRTOS为满足不同场景需求,设计了标准列表项(ListItem_…...

2025最新群智能优化算法:山羊优化算法(Goat Optimization Algorithm, GOA)求解23个经典函数测试集,MATLAB

一、山羊优化算法 山羊优化算法&#xff08;Goat Optimization Algorithm, GOA&#xff09;是2025年提出的一种新型生物启发式元启发式算法&#xff0c;灵感来源于山羊在恶劣和资源有限环境中的适应性行为。该算法旨在通过模拟山羊的觅食策略、移动模式和躲避寄生虫的能力&…...

网络基础(一)【网络发展/认识协议/网络 VS 系统/以太网通信原理/重谈协议/网络中的地址管理】

网络基础&#xff08;一&#xff09; 1. 网络的发展2. 认识协议3. 网络 VS 系统4. 以太网通信原理5. 重谈协议6. 网络中的地址管理 1. 网络的发展 最开始时&#xff0c;计算机之间相互独立。 但是为了协作完成一些任务&#xff0c;就产生了计算机之间相互通讯的需求&#xff0c…...

支付宝当面付java,php,sdk下载

SDK & Demo 获取 - 支付宝文档中心 开放平台服务端 SDK 为了帮助开发者调用开放接口&#xff0c;支付宝提供了开放平台服务端 SDK&#xff0c;包含 Java、PHP、NodeJS、Python 和 .NET 等语言版本&#xff0c;DEMO 中封装了签名 & 验签、HTTP 接口请求等基础功能。 详…...

学习threejs,Animation、Core、CustomBlendingEquation、Renderer常量汇总

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️Animation常量汇总1.1.1 循…...

常用无功功率算法的C语言实现(二)

0 前言 尽管数字延迟法和积分移相法在不间断采样的无功功率计算中得到了广泛应用,但它们仍存在一些固有缺陷。 对于数字延迟法而言,其需要额外存储至少1/4周期的采样点,在高采样频率的场景下,这对存储资源的需求不可忽视。而积分移相法虽然避免了额外的存储开销,但为了抑制…...

易基因特异性R-loop检测整体研究方案

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 01.技术简述 R-loop是由DNA:RNA 杂交体和被置换的单链DNA组成的三链核酸结构&#xff0c;广泛参与基因转录、表观遗传调控及DNA修复等关键生物学过程。异常的R-loop积累会导致基因组不稳…...

装饰器模式--RequestWrapper、请求流request无法被重复读取

目录 前言一、场景二、原因分析三、解决四、更多 前言 曾经遇见这么一段代码&#xff0c;能看出来是把request又重新包装了一下&#xff0c;核心信息都不会改变 后面了解到这叫 装饰器模式&#xff08;Decorator Pattern&#xff09; &#xff1a;也称为包装模式(Wrapper Pat…...

STM32-I2C通信协议

目录 一&#xff1a;什么是I2C通信协议 二&#xff1a;I2C通信 三&#xff1a;I2C时序图 四&#xff1a;面试常见问题 一&#xff1a;什么是I2C通信协议 I2C&#xff08;Inter-Integrated Circuit&#xff09;协议是一种串口通信协议&#xff0c;用于在集成电路之间传输数…...

Unity开发——CanvasGroup组件介绍和应用

CanvasGroup是Unity中用于控制UI的透明度、交互性和渲染顺序的组件。 一、常用属性的解释 1、alpha&#xff1a;控制UI的透明度 类型&#xff1a;float&#xff0c;0.0 ~1.0&#xff0c; 其中 0.0 完全透明&#xff0c;1.0 完全不透明。 通过调整alpha值可以实现UI的淡入淡…...

头歌作业-mysql数据库系统(全部)

每个作业只包含重要的建表代码&#xff0c;需要先进入数据库&#xff0c;创建基本的数据库之后才能使用下述命令创建表结构 MySql数据库-初识MySql 第一关&#xff1a;创建数据库 create database MyDb;第二关&#xff1a;创建表 create table t_emp(id int,name varchar(32…...

DeepSeek开启AI办公新模式,WPS/Office集成DeepSeek-R1本地大模型!

从央视到地方媒体&#xff0c;已有多家媒体机构推出AI主播&#xff0c;最近杭州文化广播电视集团的《杭州新闻联播》节目&#xff0c;使用AI主持人进行新闻播报&#xff0c;且做到了0失误率&#xff0c;可见AI正在逐渐取代部分行业和一些重复性的工作&#xff0c;这一现象引发很…...

mitt 依赖库详解

一、概述 mitt 是一个极其轻量级的 JavaScript 事件发射器库&#xff0c;实现了发布-订阅模式。该模式允许对象间松散耦合&#xff0c;一个对象&#xff08;发布者&#xff09;可以发布事件&#xff0c;而其他对象&#xff08;订阅者&#xff09;可以监听这些事件并作出响应。…...

C语言100天练习题【记录本】

C语言经典100题&#xff08;手把手 编程&#xff09; 可以在哔哩哔哩找到&#xff08;url:C语言经典100题&#xff08;手把手 编程&#xff09;_哔哩哔哩_bilibili&#xff09; 已解决的天数&#xff1a;一&#xff0c;二&#xff0c;五&#xff0c;六&#xff0c;八&#xf…...

DeepSeek【部署 03】客户端应用ChatBox、AnythingLLM及OpenWebUI部署使用详细步骤

DeepSeek客户端应用 1.ChatBox2.AnythingLLM3.OpenWebUI4.总结 客户端软件提供可视化的模型及参数配置&#xff0c;人性化的对话窗口及文件上传功能&#xff0c;大大降低了大模型的使用门槛。 1.ChatBox Chatbox AI 是一款 AI 客户端应用和智能助手&#xff0c;支持众多先进的…...

Python图形编程之EasyGUI: msgbox的用法

1 EasyGUI: msgbox的用法 1.1 基础用法&#xff1a;只显示信息 示例代码&#xff1a; from easygui import * msgbox("Hello, world!")效果&#xff1a; 1.2 扩展用法1&#xff1a;设置标题 示例代码&#xff1a; from easygui import * msgbox("Hello, …...

计算机底层知识一——从编程语言到可执行程序

好久没写博客了&#xff0c;近段时间事情比较杂&#xff0c;最近终于有时间回归了。其余代码写久了就会遇到许多奇奇怪怪的问题&#xff0c;这些问题绕不开许多底层知识&#xff0c;比如缺少动态依赖库、idea编译失败等等&#xff0c;虽然通过百度等搜索引擎&#xff0c;亦或是…...

中性点直接接地电网接地故障Simulink仿真

1.模型简介 本仿真模型基于MATLAB/Simulink&#xff08;版本MATLAB 2017Ra&#xff09;软件。建议采用matlab2017 Ra及以上版本打开。&#xff08;若需要其他版本可联系代为转换&#xff09; 2.系统仿真图&#xff1a; 3.中性点直接接地电网接地故障基本概念&#xff08;本仿…...

解决Jenkins默认终止Shell产生服务进程的问题

1、Windows环境 Jenkins进行Build steps的使用Execute Windows batch command启动微服务&#xff08;Jar包&#xff09;&#xff0c;Jenkins会默认终止Shell产生的服务进程&#xff0c;而在命令行能够正常运行的服务进程。 1.1 使用命令行启动服务是正常 使用命令行执行 正常…...

Spring Boot 项目中 Redis 常见问题及解决方案

目录 缓存穿透缓存雪崩缓存击穿Redis 连接池耗尽Redis 序列化问题总结 1. 缓存穿透 问题描述 缓存穿透是指查询一个不存在的数据&#xff0c;由于缓存中没有该数据&#xff0c;请求会直接打到数据库上&#xff0c;导致数据库压力过大。 解决方案 缓存空值&#xff1a;即使…...

STM32 I2C驱动开发全解析:从理论到实战 | 零基础入门STM32第五十步

主题内容教学目的/扩展视频I2C总线电路原理&#xff0c;跳线设置&#xff0c;I2C协议分析。驱动程序与调用。熟悉I2C总线协议&#xff0c;熟练调用。 师从洋桃电子&#xff0c;杜洋老师 &#x1f4d1;文章目录 引言一、I2C驱动分层架构二、I2C总线驱动代码精析2.1 初始化配置&a…...

RuleOS:区块链开发的“破局者”,开启Web3新纪元

RuleOS&#xff1a;区块链开发的“破冰船”&#xff0c;驶向Web3的星辰大海 在区块链技术的浩瀚宇宙中&#xff0c;一群勇敢的探索者正驾驶着一艘名为RuleOS的“破冰船”&#xff0c;冲破传统开发的冰层&#xff0c;驶向Web3的星辰大海。这艘船&#xff0c;正以一种前所未有的姿…...

manus本地部署使用体验

manus部署 https://github.com/mannaandpoem/OpenManus git clone https://github.com/mannaandpoem/OpenManus.git 或者手工下载zip包解压&#xff0c;包很小&#xff0c;只有几百K。 cd OpenManus-main #创建python环境&#xff0c;有python3的可以用python3 python -m ven…...

OpenCV 拆分、合并图像通道方法及复现

视频讲解 OpenCV 拆分、合并图像通道方法及复现 环境准备&#xff1a;安装 OpenCV 库&#xff08;pip install opencv-python&#xff09; 内容&#xff1a; 1. 读取任意图片&#xff08;支持 jpg/png 等格式&#xff09; 2. 使用 split () 函数拆解成 3 个单色通道&#xf…...