摘要:树形结构是计算机科学的基石,而二叉树则是其中最闪耀的明珠。本文将简单介绍树和二叉树的概念,为后续数据结构和算法的学习打一个基础
树是一种分层抽象模型,它用节点间的父子关系打破了线性结构的桎梏。就像现实中的金字塔:
树T是一个满足以下条件的n(n≥0)个节点的有限集合:
通过家族关系类比理解(以图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) | 互不相交的树的集合 | 删除根节点后得到森林 |
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树 | 每个边代表一个字符 | 输入法词库 |
以公司组织架构为例:
CEO
/ | \
VP1 VP2 VP3
/ \ / | \
M1 M2 M3 M4 M5
广度优先遍历(BFS)
访问顺序:CEO → VP1 → VP2 → VP3 → M1 → M2 → M3 → M4 → M5
场景:计算组织架构层级
深度优先遍历(DFS)
Z型遍历
输出:CEO ← VP1 → VP2 ← VP3 → M3 ← M4 → M5
场景:DNA序列分析
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']]
/
├── bin
├── etc
│ ├── apt
│ └── network
├── home
│ ├── user1
│ └── user2
└── usr
<html>
<head>
<title>Pagetitle>
head>
<body>
<div class="content">
<p>Hello Worldp>
div>
body>
html>
对应的DOM树:
html
/ \
head body
| |
title div
| |
"Page" p
|
"Hello World"
是否周末?
/ \
是 否
/ \
天气好? 需要加班?
/ \ / \
外出 宅家 加班 看电影
特性1:第i层最多有2^(i-1)个节点
证明:数学归纳法
特性2:深度为h的二叉树最多有 2 h − 1 2^{h -1} 2h−1个节点
应用:快速判断树是否满二叉树
概念:
满二叉树:除了叶子节点外,其余节点都有左右子节点
完全二叉树:可以是满二叉树,也可以是某个满二叉树删除最后一层的最后若干个节点。
用数组存储完全二叉树
将节点按层序存入数组:
1(0)
/ \
2(1) 3(2)
/ \
4(3) 5(4)
数组表示:[1,2,3,4,5]
父子关系计算:
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
查找效率对比:
数据结构 | 平均时间复杂度 | 最坏情况 |
---|---|---|
数组(无序) | 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树(通过旋转保持平衡)或红黑树(通过颜色标记)
以左旋为例:
不平衡点(A)
\
B
\
C
旋转后:
B
/ \
A C
本文就树的概念做一个简要介绍,其中涉及到的更深入的概念,随后还会涉及到。
/* 树和二叉树 已完结
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)