【数据结构与算法-Day 19】告别线性世界,一文掌握树(Tree)的核心概念与表示法

Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来

Python系列文章目录

PyTorch系列文章目录

机器学习系列文章目录

深度学习系列文章目录

Java系列文章目录

JavaScript系列文章目录

Python系列文章目录

Go语言系列文章目录

Docker系列文章目录

数据结构与算法系列文章目录

01-【数据结构与算法-Day 1】程序世界的基石:到底什么是数据结构与算法?
02-【数据结构与算法-Day 2】衡量代码的标尺:时间复杂度与大O表示法入门
03-【数据结构与算法-Day 3】揭秘算法效率的真相:全面解析O(n^2), O(2^n)及最好/最坏/平均复杂度
04-【数据结构与算法-Day 4】从O(1)到O(n²),全面掌握空间复杂度分析
05-【数据结构与算法-Day 5】实战演练:轻松看懂代码的时间与空间复杂度
06-【数据结构与算法-Day 6】最朴素的容器 - 数组(Array)深度解析
07-【数据结构与算法-Day 7】告别数组束缚,初识灵活的链表 (Linked List)
08-【数据结构与算法-Day 8】手把手带你拿捏单向链表:增、删、改核心操作详解
09-【数据结构与算法-Day 9】图解单向链表:从基础遍历到面试必考的链表反转
10-【数据结构与算法-Day 10】双向奔赴:深入解析双向链表(含图解与代码)
11-【数据结构与算法-Day 11】从循环链表到约瑟夫环,一文搞定链表的终极形态
12-【数据结构与算法-Day 12】深入浅出栈:从“后进先出”原理到数组与链表双实现
13-【数据结构与算法-Day 13】栈的应用:从括号匹配到逆波兰表达式求值,面试高频考点全解析
14-【数据结构与算法-Day 14】先进先出的公平:深入解析队列(Queue)的核心原理与数组实现
15-【数据结构与算法-Day 15】告别“假溢出”:深入解析循环队列与双端队列
16-【数据结构与算法-Day 16】队列的应用:广度优先搜索(BFS)的基石与迷宫寻路实战
17-【数据结构与算法-Day 17】揭秘哈希表:O(1)查找速度背后的魔法
18-【数据结构与算法-Day 18】面试必考!一文彻底搞懂哈希冲突四大解决方案:开放寻址、拉链法、再哈希
19-【数据结构与算法-Day 19】告别线性世界,一文掌握树(Tree)的核心概念与表示法



摘要

在数据结构的世界里,我们已经探索了数组、链表、栈和队列等线性结构,它们如同串成一线的珍珠,元素之间维持着简单的一对一关系。然而,现实世界充满了复杂的层级关系,例如公司组织架构、文件系统目录、家族谱系等。为了高效地模拟这些“一对多”的关系,一种全新的、功能强大的非线性结构——**树(Tree)**应运而生。本文将作为您踏入非线性结构世界的第一站,系统地为您讲解树的基本概念,从最基础的节点、边,到描述其特性的深度、高度、度,并深入探讨在计算机中表示树的两种主流方法。掌握这些基础,是深入学习二叉树、平衡树、堆等高级数据结构不可或缺的基石。

一、为什么需要树?—— 从线性到非线性

在深入树的细节之前,我们首先要理解,为什么我们需要从熟悉的线性结构迈向非线性结构。

1.1 线性结构的局限性

线性数据结构,如数组和链表,其核心特征是数据元素之间存在“一对一”的线性关系。每个元素(除了首尾)都有一个唯一的前驱和一个唯一的后继。这种结构非常适合表示顺序序列,比如排队的人群、文章的段落。

然而,当我们需要表示以下关系时,线性结构就显得力不从心了:

  • 层级关系:公司的组织架构中,一个经理可以管理多个员工。
  • 分类关系:图书分类中,一个大类(如“计算机科学”)下可以有多个子类(如“编程语言”、“数据库”)。
  • 从属关系:电脑的文件系统中,一个文件夹可以包含多个文件和其他文件夹。

用线性结构来强行表示这些关系,会变得异常复杂和低效。

1.2 树:描述层级关系的神器

为了解决上述问题,**树(Tree)**结构应运而生。树是一种抽象数据类型(ADT),它由 n(n>=0)个有限节点组成一个具有层次关系的集合。当 n=0 时,我们称之为空树。

树结构能够完美地模拟现实世界中的层级关系,它直观、高效,是我们工具箱中不可或缺的利器。

下面是一个典型的树形结构——公司组织架构图:

CEO
技术部 CTO
市场部 CMO
行政部 CAO
后端开发组
前端开发组
测试组
品牌推广
销售渠道
工程师A
工程师B
工程师C

这张图清晰地展示了“一对多”的隶属关系,这就是树的威力所在。

二、深入浅出:树(Tree)的核心术语

为了能够准确地讨论和使用树,我们需要学习一套标准的“行话”。下面,我们将通过一个示例图来解释树的所有核心术语。

示例树:

A
B
C
D
E
F
G
H
I

2.1 基础构成元素

2.1.1 节点 (Node)

节点是树的基本组成单元。在图中,A, B, C, D, E, F, G, H, I 都是节点。一个节点通常包含两个部分:

  • 数据域 (Data):存储节点的具体信息,如员工姓名、文件夹名称等。
  • 指针域 (Pointers):存储指向其子节点的链接。

2.1.2 边 (Edge)

边是连接两个节点之间的线,代表它们之间的直接关系。例如,从 AB 的箭头就是一条边。

2.2 节点间的关系与角色

2.2.1 根节点 (Root)

一棵树有且仅有一个没有父节点的节点,我们称之为根节点。它是树的入口。

  • 示例:节点 A 是这棵树的根节点。

2.2.2 父节点 (Parent) 与 子节点 (Child)

如果一个节点 X 连接到另一个节点 Y,那么 X 称为 Y父节点Y 称为 X子节点

  • 示例ABCD 的父节点;BCDA 的子节点。

2.2.3 兄弟节点 (Sibling)

拥有相同父节点的节点互称为兄弟节点

  • 示例BCD 互为兄弟节点。HI 互为兄弟节点。

2.2.4 叶子节点 (Leaf / Terminal Node)

没有任何子节点的节点称为叶子节点或终端节点。

  • 示例D, E, G, H, I 都是叶子节点。

2.2.5 内部节点 (Internal / Non-terminal Node)

除了根节点和叶子节点之外的所有节点,即至少有一个子节点的非根节点,称为内部节点。有时也宽泛地指所有非叶子节点。

  • 示例B, C, F 是内部节点。A 也是一个非叶子节点。

2.3 树的整体特性

2.3.1 节点的度 (Degree)

一个节点拥有的子树(或子节点)的数量称为该节点的度。树中所有节点度的最大值称为树的度

  • 示例
    • 节点 A 的度为 3。
    • 节点 F 的度为 2。
    • 叶子节点 G 的度为 0。
    • 这棵树的度为 3(取所有节点度的最大值)。

2.3.2 节点的层次 (Level)

从根节点开始定义,根在第 1 层,根的子节点在第 2 层,以此类推。

  • 示例
    • Level 1: A
    • Level 2: B, C, D
    • Level 3: E, F, G
    • Level 4: H, I

注意:在某些教材或定义中,根节点的层次可能从 0 开始。这是一种约定俗成的差异,理解其相对性即可,在具体问题中保持一致性是关键。

2.3.3 树的深度 (Depth)

树的深度是指树中节点的最大层次。它描述了树的“纵向”有多深。

  • 示例:这棵树的最大层次是 4,所以树的深度为 4。

关于节点的深度:从根节点到该节点所经过的的数量。根节点的深度为 0,其子节点的深度为 1,以此类推。一棵树的深度等于其最深叶子节点的深度。

2.3.4 树的高度 (Height)

树的高度是指树中节点的最大高度。

  • 示例:这棵树的高度为 3。

关于节点的高度:从该节点到其最远叶子节点所经过的的数量。叶子节点的高度为 0,其父节点的高度是其所有子节点高度最大值加 1。一棵树的高度等于其根节点的高度。

(1)深度与高度的辨析

深度和高度是两个容易混淆但至关重要的概念。

  • 深度 (Depth):是“自上而下”看的,从根节点出发。
  • 高度 (Height):是“自下而上”看的,从叶子节点出发。
概念参考系方向
深度根节点从根到当前节点
高度叶子节点从当前节点到最远叶子

对于整棵树而言,树的高度等于树的深度。但对于任意一个节点,其高度和深度通常是不同的。

2.4 特殊概念

2.4.1 子树 (Subtree)

树中任意一个节点和它所有的后代(子孙)节点组成的集合,也构成一棵树,称为原树的子树

  • 示例:以节点 B 为根的 B-E-F-H-I 结构就是 A 树的一棵子树。

2.4.2 森林 (Forest)

m (m>=0) 棵互不相交的树的集合称为森林。把一棵树的根节点删除,其所有的子树就构成了一个森林。

  • 示例:如果我们删除根节点 A,那么以 BCD 为根的三棵树就组成了一个森林。

三、树的计算机表示法

理解了树的理论概念后,我们如何在代码中把它“造”出来呢?主要有两种方法:数组表示法和链式表示法。

3.1 数组表示法 (父节点表示法)

这种方法使用一个一维数组来存储树的各个节点。数组的索引(下标)可以唯一标识一个节点,而数组元素的值则存储该节点的父节点在数组中的索引。根节点没有父节点,通常用一个特殊值(如 -1)表示。

示例:
我们将上面的示例树(稍作简化,假设节点用数字 0-8 表示 A-I)用父节点表示法存储:

节点:  A  B  C  D  E  F  G  H  I
索引:  0  1  2  3  4  5  6  7  8
父索引:-1  0  0  0  1  1  2  5  5 
数组索引 (节点)0 (A)1 (B)2 ©3 (D)4 (E)5 (F)6 (G)7 (H)8 (I)
父节点索引-100011255
数据dataAdataBdataCdataDdataEdataFdataGdataHdataI

优点:

  • 实现简单,易于理解。
  • 查找任意节点的父节点非常快,时间复杂度为 O ( 1 ) O(1) O(1)

缺点:

  • 查找任意节点的子节点很慢,需要遍历整个数组,时间复杂度为 O ( n ) O(n) O(n)
  • 如果树的结构频繁变动(增加、删除节点),维护数组会非常麻烦。
  • 可能造成空间浪费。

3.2 链式表示法

链式表示法克服了数组表示法的一些缺点,是更常用和灵活的方法。其中,孩子兄弟表示法是最高效和通用的链式表示方法。

3.2.1 孩子兄弟表示法 (Child-Sibling Representation)

这种表示法的核心思想是:每个节点包含两个指针(或引用):

  1. 一个指针指向它的第一个孩子节点 (first child)
  2. 另一个指针指向它的下一个兄弟节点 (next sibling)

通过这种巧妙的设计,任意度的树都可以用这种结构来表示,每个节点只需要固定数量的指针。

(1)代码实现

下面是孩子兄弟表示法的节点结构定义示例(以 Python 为例):

class TreeNode:
    """
    树节点类(孩子兄弟表示法)
    """
    def __init__(self, value):
        self.value = value            # 节点存储的数据
        self.first_child = None     # 指向第一个孩子的引用
        self.next_sibling = None    # 指向下一个兄弟的引用

# 构建示例树的一部分
root = TreeNode('A')
b = TreeNode('B')
c = TreeNode('C')
d = TreeNode('D')

# A的孩子是B, C, D
root.first_child = b
b.next_sibling = c
c.next_sibling = d

e = TreeNode('E')
f = TreeNode('F')

# B的孩子是E, F
b.first_child = e
e.next_sibling = f

print(f"根节点 {root.value} 的第一个孩子是 {root.first_child.value}")
print(f"节点 {b.value} 的下一个兄弟是 {b.next_sibling.value}")

3.3 表示法对比总结

特性父节点表示法 (数组)孩子兄弟表示法 (链式)
查找父节点极快 ( O ( 1 ) O(1) O(1))较慢,需要遍历 (最坏 O ( n ) O(n) O(n))
查找子节点慢,需遍历整个数组 ( O ( n ) O(n) O(n))较快,遍历孩子链表
查找兄弟节点慢,需遍历整个数组 ( O ( n ) O(n) O(n))快,直接访问 next_sibling ( O ( 1 ) O(1) O(1))
增删节点困难,可能需要移动大量元素灵活,只需修改指针
空间复杂度固定为 O ( n ) O(n) O(n) O ( n ) O(n) O(n),但节点对象开销稍大
适用场景静态树,主要关心父子关系动态树,需要频繁操作和遍历

在绝大多数应用场景中,孩子兄弟表示法因其灵活性和高效的遍历能力而成为首选。

四、总结

恭喜你,成功开启了非线性数据结构的大门!今天我们系统地学习了树的基础知识,现在让我们回顾一下核心要点:

  1. 树的价值:树结构是为表示“一对多”的层级关系而生的,它弥补了线性结构在这方面的不足,是计算机科学中模拟现实世界层级模型的基础。

  2. 核心术语:我们掌握了一套描述树的通用语言,包括节点、边、根、父、子、兄弟、叶子节点等基本角色,以及度、层次、深度、高度等衡量树形态的关键指标。请务必区分深度(自上而下)高度(自下而上)

  3. 存储实现:我们探讨了两种主要的计算机表示法。**父节点表示法(数组)简单但操作受限,适用于静态场景。而孩子兄弟表示法(链式)**通过巧妙的firstChildnextSibling指针,实现了对任意树的灵活、高效存储,是动态树结构的首选方案。

打好这个坚实的基础后,我们下一篇文章将聚焦于一种最重要、最常见的树——二叉树,敬请期待!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吴师兄大模型

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值