004 树与二叉树:从原理到实战

摘要:树形结构是计算机科学的基石,而二叉树则是其中最闪耀的明珠。本文将简单介绍树和二叉树的概念,为后续数据结构和算法的学习打一个基础


一、树(Tree):数据世界的金字塔结构

1. 树的本质

树是一种分层抽象模型,它用节点间的父子关系打破了线性结构的桎梏。就像现实中的金字塔:

  • 根节点是塔尖,掌握全局
  • 内部节点是中层管理者,承上启下
  • 叶子节点是基层执行者,专注细节
树的数学定义(严谨版)

树T是一个满足以下条件的n(n≥0)个节点的有限集合:

  1. 当n=0时,称为空树
  2. 当n>0时,存在唯一根节点,其余节点分为m(m≥0)个互不相交的子树

2. 树的20个核心术语详解

通过家族关系类比理解(以图1为例):

复制代码
        董事长(CEO)
        /    |    \
     CTO    CFO   COO
     /  \         /   \
 Dev1  Dev2   Ops1  Ops2
术语 解释 示例
度 (Degree) 节点的子节点数 CTO的度为2
路径 (Path) 节点间的边序列 CEO→CTO→Dev1是路径
兄弟节点 (Sibling) 同父节点的节点 Dev1和Dev2是兄弟
堂兄弟节点 同层但父节点不同 Dev1与Ops1是堂兄弟
祖先节点 (Ancestor) 从根到该节点的路径上的所有节点 CEO是Dev1的祖先
后代节点 (Descendant) 某节点子树中的所有节点 CTO的后代是Dev1,Dev2
森林 (Forest) 互不相交的树的集合 删除根节点后得到森林

3. 树的分类大全(7种维度)

维度1:节点分支数
python 复制代码
class TreeNode:
    def __init__(self, data):
        self.data = data
        self.children = []  # 普通树的实现方式
        
# 二叉树节点
class BinaryTreeNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
类型 特点 应用场景
普通树 子节点数无限制 文件系统
二叉树 每个节点最多2个子节点 表达式计算
Trie树 每个边代表一个字符 输入法词库
维度2:节点关系特性
  • 有序树:子节点顺序不可交换(如二叉树)
  • 无序树:子节点顺序无关(如公司部门结构)

4. 树的5种遍历方式详解(非二叉树)

以公司组织架构为例:

复制代码
        CEO
     /   |   \
   VP1  VP2  VP3
  /  \       / | \
M1   M2   M3 M4 M5
  1. 广度优先遍历(BFS)

    访问顺序:CEO → VP1 → VP2 → VP3 → M1 → M2 → M3 → M4 → M5

    场景:计算组织架构层级

  2. 深度优先遍历(DFS)

    • 前序:CEO → VP1 → M1 → M2 → VP2 → VP3 → M3 → M4 → M5
      (适用于复制树结构)
    • 后序:M1 → M2 → VP1 → VP2 → M3 → M4 → M5 → VP3 → CEO
      (适用于计算文件夹大小)
    • 中序:仅对二叉树有意义
  3. Z型遍历

    输出:CEO ← VP1 → VP2 ← VP3 → M3 ← M4 → M5

    场景:DNA序列分析

代码实现(Python)
python 复制代码
from collections import deque

class GeneralTree:
    def __init__(self, root):
        self.root = root

    def bfs(self):
        if not self.root:
            return []
        result = []
        queue = deque([self.root])
        while queue:
            level_size = len(queue)
            current_level = []
            for _ in range(level_size):
                node = queue.popleft()
                current_level.append(node.data)
                for child in node.children:
                    queue.append(child)
            result.append(current_level)
        return result  # 返回分层结果

# 示例用法
ceo = TreeNode("CEO")
vp1 = TreeNode("VP1")
vp2 = TreeNode("VP2")
vp3 = TreeNode("VP3")
ceo.children = [vp1, vp2, vp3]
vp1.children = [TreeNode("M1"), TreeNode("M2")]
vp3.children = [TreeNode("M3"), TreeNode("M4"), TreeNode("M5")]

tree = GeneralTree(ceo)
print("BFS结果:", tree.bfs())
# 输出: [['CEO'], ['VP1', 'VP2', 'VP3'], ['M1', 'M2', 'M3', 'M4', 'M5']]

5. 树的6大经典应用场景

场景1:Linux文件系统
复制代码
/
├── bin
├── etc
│   ├── apt
│   └── network
├── home
│   ├── user1
│   └── user2
└── usr
  • 路径表示:/home/user1/docs/file.txt
  • 操作特点:快速定位文件(类似B+树索引)
场景2:XML/HTML解析
html 复制代码
<html>
  <head>
    <title>Page</title>
  </head>
  <body>
    <div class="content">
      <p>Hello World</p>
    </div>
  </body>
</html>

对应的DOM树:

复制代码
           html
         /     \
     head       body
      |          |
    title       div
     |           |
   "Page"       p
                 |
             "Hello World"
场景3:人工智能决策树
复制代码
          是否周末?
         /        \
    是            否
    /              \
天气好?          需要加班?
  /  \             /    \
外出 宅家        加班   看电影
  • 信息增益:通过熵值计算最佳分裂属性
  • 剪枝优化:防止过拟合

二、二叉树:简洁与高效的完美平衡

1. 二叉树的5大特性证明

特性1 :第i层最多有2^(i-1)个节点
证明:数学归纳法

  • 基础:i=1时,根节点1个=2^0 ✔️
  • 归纳:假设第k层最多 2 k − 1 2^{k-1} 2k−1节点,则第k+1层最多 2 ⋅ 2 k − 1 = 2 k 2 \cdot 2^{k-1}=2^k 2⋅2k−1=2k ✔️

特性2 :深度为h的二叉树最多有 2 h − 1 2^{h -1} 2h−1个节点
应用:快速判断树是否满二叉树

2. 完全二叉树的数组存储技巧

概念 :

满二叉树:除了叶子节点外,其余节点都有左右子节点

完全二叉树:可以是满二叉树,也可以是某个满二叉树删除最后一层的最后若干个节点。

用数组存储完全二叉树

将节点按层序存入数组:

复制代码
        1(0)
       /   \
    2(1)   3(2)
   /  \ 
4(3) 5(4)

数组表示:[1,2,3,4,5]

父子关系计算

  • 父节点索引 = (i-1)//2
  • 左子节点索引 = 2i +1
  • 右子节点索引 = 2i +2
python 复制代码
class ArrayBinaryTree:
    def __init__(self, array):
        self.array = array
    
    def parent(self, index):
        return (index-1)//2 if index >0 else None
    
    def left_child(self, index):
        left = 2*index +1
        return left if left < len(self.array) else None

# 示例
tree = ArrayBinaryTree([1,2,3,4,5])
print(tree.left_child(0))  # 输出1

3. 二叉搜索树(BST)的平衡之道

查找效率对比

数据结构 平均时间复杂度 最坏情况
数组(无序) O(n) O(n)
BST O(log n) O(n)
平衡BST O(log n) O(log n)

BST退化成链表的危险

复制代码
1
 \
  2
   \
    3
     \
      4

此时查找效率降级为O(n)

解决方案

引入AVL树(通过旋转保持平衡)或红黑树(通过颜色标记)


三、平衡二叉树

1. AVL树旋转的四种情况

以左旋为例:

复制代码
不平衡点(A)
     \
      B
       \
        C

旋转后:

复制代码
      B
     / \
    A   C

五、知识图谱:树形结构的演进之路

树 二叉树 N叉树 二叉搜索树 AVL树 红黑树 B树 B+树 数据库索引 TreeMap 快速查找

总结

本文就树的概念做一个简要介绍,其中涉及到的更深入的概念,随后还会涉及到。

推荐练习

/* 树和二叉树 已完结
144. 二叉树的前序遍历(简单)
94. 二叉树的中序遍历(简单)
145. 二叉树的后序遍历(简单)
102. 二叉树的层序遍历(中等)
107. 二叉树的层序遍历 II(中等)
199. 二叉树的右视图(中等)
105. 从前序与中序遍历序列构造二叉树(中等)
106. 从中序与后序遍历序列构造二叉树(中等)
108. 将有序数组转换为二叉搜索树(简单)
101. 对称二叉树(简单)
104. 二叉树的最大深度(简单)
111. 二叉树的最小深度(简单)
110. 平衡二叉树(简单)
112. 路径总和(简单)
113. 路径总和 II(中等)
124. 二叉树中的最大路径和(困难)
98. 验证二叉搜索树(中等)
99. 恢复二叉搜索树(中等)
230. 二叉搜索树中第K小的元素(中等)
450. 删除二叉搜索树中的节点(中等)
235. 二叉搜索树的最近公共祖先(简单)
236. 二叉树的最近公共祖先(中等)
297. 二叉树的序列化与反序列化(困难)
501. 二叉搜索树中的众数(简单,可用Morris中序遍历优化空间)
226. 翻转二叉树(简单)
543. 二叉树的直径(简单)
617. 合并二叉树(简单)
96. 不同的二叉搜索树(中等)
337. 打家劫舍 III(中等,树形DP)

相关推荐
朱剑君34 分钟前
排序算法——基数排序
算法·排序算法
COOCC141 分钟前
PyTorch 实战:从 0 开始搭建 Transformer
人工智能·pytorch·python·深度学习·算法·机器学习·transformer
yzlAurora1 小时前
删除链表倒数第N个节点
数据结构·链表
进击的小白菜2 小时前
如何高效实现「LeetCode25. K 个一组翻转链表」?Java 详细解决方案
java·数据结构·leetcode·链表
拾忆-eleven2 小时前
C++算法(19):整数类型极值,从INT_MIN原理到跨平台开发实战
数据结构·c++·算法
JK0x072 小时前
代码随想录算法训练营 Day39 动态规划Ⅶ 打家劫舍
算法·动态规划
blammmp3 小时前
算法专题四:前缀和
java·开发语言·算法
望未来无悔3 小时前
系统学习算法:动态规划(斐波那契+路径问题)
java·算法
明月看潮生3 小时前
青少年编程与数学 02-018 C++数据结构与算法 25课题、图像处理算法
c++·图像处理·算法·青少年编程·编程与数学
我是一只鱼02233 小时前
LeetCode算法题 (反转链表)Day17!!!C/C++
数据结构·c++·算法·leetcode·链表