
🏠个人主页:得鹿梦鱼
🎬作者简介:C/C++/JAVA后端开发学习者
❄️个人专栏:JAVA SE、数据结构与算法(JAVA)
✨ 从来绝巘须孤往,万里同尘即玉京
文章目录
- [二叉树基础精讲(上):树形结构 · 二叉树概念 · 性质 · 遍历 · 基础操作全解析](#二叉树基础精讲(上):树形结构 · 二叉树概念 · 性质 · 遍历 · 基础操作全解析)
-
- [📝 文章摘要](#📝 文章摘要)
- [🔍 前置知识回顾](#🔍 前置知识回顾)
- 一、树型结构
-
- [1. 概念](#1. 概念)
- [2. 相关概念](#2. 相关概念)
- [3. 树的表示方法](#3. 树的表示方法)
- 二、二叉树
- [🎯 核心考点总结](#🎯 核心考点总结)
- [✍️ 写在最后](#✍️ 写在最后)

二叉树基础精讲(上):树形结构 · 二叉树概念 · 性质 · 遍历 · 基础操作全解析
📝 文章摘要
阅读时长 :25 分钟
适合人群:
- 数据结构入门学习者 → 重点:树形结构概念、二叉树定义与性质
- 算法与笔试备考同学 → 重点:二叉树公式推导、完全二叉树高度计算
- Java 编程学习者 → 重点:二叉树节点定义、前中后序遍历
- 复习总结同学 → 重点:公式记忆、代码模板、递归思路
本文内容 :全覆盖树形结构 、二叉树概念 、满二叉树 & 完全二叉树 、5 大性质 、4 种遍历 、节点/叶子/高度/层序遍历等基础操作,从理论到代码,一次性打好二叉树基础。
🔍 前置知识回顾
学习本文前你需要掌握:
- 线性表、栈、队列基础结构
- 递归思想与简单递归代码
- Java 类、对象、引用
- 对数、等比数列等基础数学知识
一、树型结构
1. 概念
树是一种非线性结构,像一棵倒挂的树(根朝上,叶朝下)。
- 树是递归定义的(树有根节点,根节点下有很多子树,子树根节点下又有很多子树)
- 注意:
① 子树不相交,不能有环
② 除根节点外,每个节点有且仅有一个父结点
③ 一棵n个结点的树有n-1条边
2. 相关概念
- 节点的度:一个节点含有子树的个数。如A的度为6
- 叶子节点(终端节点):度为0的节点
- 分支节点(非终端节点):度不为0的节点
- 树的度:树中各节点的度的最大值
- 根结点:一棵树中,没有双亲结点的结点。如上方树的根结点为A
- 父结点(双亲节点):若一个节点含有子结点,这个节点是其子节点的父节点
- 子节点(孩子节点):一个节点含有子树的根节点
- 兄弟节点:具有相同父节点的节点
- 节点的层次与树的高度(树的深度)
- 推荐:根结点为第1层,根的子结点为第2层,依次类推。空树高度为0
- 不推荐:根结点为第0层,根的子结点为第1层,依次类推。空树高度为-1
- 节点的子孙:以某节点为根的子树任一结点
- 节点的祖先:从根结点到该节点所经分支上的所有结点
- 森林:由一棵或多棵互不相交的树的集合
3. 树的表示方法
(1)孩子兄弟表示法(左孩子右兄弟)
(对应示例树与链式存储结构)
二、二叉树
1. 概念
- 任何一个二叉树可以分成三个部分:根节点、左子树、右子树
- 二叉树有左右之分,其子树的次序不能颠倒
- 有两种特殊的二叉树:满二叉树和完全二叉树
(1)满二叉树
一棵二叉树,如果每层的结点,都达到最大值(每层都是满的)
- 假设一棵满二叉树高度为h,节点总个数为N,则:
N = 2 h − 1 N = 2^h - 1 N=2h−1
h = log 2 ( N + 1 ) ≈ log 2 N h = \log_2(N+1) \approx \log_2 N h=log2(N+1)≈log2N
推导: 2 0 + 2 1 + ⋯ + 2 h − 1 = N 2^0 + 2^1 + \dots + 2^{h-1} = N 20+21+⋯+2h−1=N,由等比数列求和公式 2 0 ( 1 − 2 h ) 1 − 2 = 2 h − 1 = N \frac{2^0(1-2^h)}{1-2} = 2^h -1 = N 1−220(1−2h)=2h−1=N,得 h = log 2 ( N + 1 ) h = \log_2(N+1) h=log2(N+1)
(2)完全二叉树
① 前h-1层都是满的
② 最后一层不满,但最后一层从左往右都是连续的
- 假设一棵完全二叉树高度是h,节点总个数为N,则:
h = log 2 ( N + 1 + x ) ( 1 ≤ x ≤ 2 h − 1 − 1 ) h = \log_2(N+1+x) \quad (1 \le x \le 2^{h-1}-1) h=log2(N+1+x)(1≤x≤2h−1−1)
且 log 2 ( N + 2 ) ≤ h ≤ 1 + log 2 N \log_2(N+2) \le h \le 1+\log_2 N log2(N+2)≤h≤1+log2N- 当 x = 1 x=1 x=1时, h = log 2 ( N + 2 ) h = \log_2(N+2) h=log2(N+2)
- 当 x = 2 h − 1 − 1 x=2^{h-1}-1 x=2h−1−1, h = log 2 h = 1 + log 2 N h = \log_2 h = 1+\log_2 N h=log2h=1+log2N
2. 性质
(1)若规定根节点的层数是1,则一棵非空二叉树第n层上最多有 2 n − 1 2^{n-1} 2n−1个结点
(2)若规定根节点的层数是1,则高度为h的二叉树最大结点为 2 h − 1 2^h -1 2h−1
(3)对任何一棵二叉树,如果其度为0的叶子结点个数为 n 0 n_0 n0,度为2的分支结点个数为 n 2 n_2 n2,则有 n 0 = n 2 + 1 \boldsymbol{n_0 = n_2 + 1} n0=n2+1
推导 :
设度为0的结点为 n 0 n_0 n0,度为1的结点为 n 1 n_1 n1,度为2的结点为 n 2 n_2 n2,总结点和为 N N N,总边和为 E E E,则
N = n 0 + n 1 + n 2 ① N = n_0 + n_1 + n_2 \quad ① N=n0+n1+n2①
由度为0的结点不会引出边,度为1的结点会引出一条边,度为2的结点会引出两条边,得
E = n 1 × 1 + n 2 × 2 + n 0 × 0 ⟹ E = n 1 + 2 n 2 ② E = n_1 \times 1 + n_2 \times 2 + n_0 \times 0 \implies E = n_1 + 2n_2 \quad ② E=n1×1+n2×2+n0×0⟹E=n1+2n2②
由除根节点外,每个结点都有一边指向自己,得
E = N − 1 ③ E = N - 1 \quad ③ E=N−1③
联立①②③:
{ N = n 0 + n 1 + n 2 ① E = n 1 + 2 n 2 ② E = N − 1 ③ \begin{cases} N = n_0 + n_1 + n_2 & ① \\ E = n_1 + 2n_2 & ② \\ E = N - 1 & ③ \end{cases} ⎩ ⎨ ⎧N=n0+n1+n2E=n1+2n2E=N−1①②③
得 n 0 + n 1 + n 2 − 1 = n 1 + 2 n 2 n_0 + n_1 + n_2 - 1 = n_1 + 2n_2 n0+n1+n2−1=n1+2n2
得 n 0 = n 2 + 1 n_0 = n_2 + 1 n0=n2+1,证毕。
(4)若规定根节点的层数是1,具有N个结点的满二叉树高度为h,则 h = log 2 ( N + 1 ) h = \log_2(N+1) h=log2(N+1)(向上取整)
(5)对于具有n个结点的完全二叉树,如果按照由上至下、由左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有:
leftchild = parent * 2 + 1rightchild = parent * 2 + 2parent = (child - 1) / 2(child为leftchild或rightchild)
(连续的)
练习
一棵完全二叉树的结点为531,那么这棵树的高度为 10
假设这棵树的高度为h,最后一层缺了X个
2 h − 1 − x = 531 , x ∈ [ 0 , 2 h − 1 − 1 ] 2^h - 1 - x = 531, \quad x \in [0, 2^{h-1}-1] 2h−1−x=531,x∈[0,2h−1−1]
左边 ∈ [ 2 h − 1 , 2 h − 2 ] \in [2^{h-1}, 2^h - 2] ∈[2h−1,2h−2]
{ 2 9 = 512 2 10 = 1024 2 11 = 2048 ⟹ { h ≠ 9 , 531 ∉ [ 256 , 510 ] h = 10 , 531 ∈ [ 512 , 1022 ] h ≠ 11 , 531 ∉ [ 1024 , 2046 ] \begin{cases} 2^9 = 512 \\ 2^{10} = 1024 \\ 2^{11} = 2048 \end{cases} \implies \begin{cases} h \neq 9, 531 \notin [256, 510] \\ h = 10, 531 \in [512, 1022] \\ h \neq 11, 531 \notin [1024, 2046] \end{cases} ⎩ ⎨ ⎧29=512210=1024211=2048⟹⎩ ⎨ ⎧h=9,531∈/[256,510]h=10,531∈[512,1022]h=11,531∈/[1024,2046]
练习2
在具有2n个结点的完全二叉树中,叶子结点的个数为 n \boldsymbol{n} n
设度为0的结点为 n 0 n_0 n0,度为1的结点为 n 1 n_1 n1,度为2的结点为 n 2 n_2 n2,则
{ n 0 + n 1 + n 2 = 2 n n 0 = n 2 + 1 ⟹ 2 n 0 + n 1 − 1 = 2 n ⟹ n 0 = n + 1 − n 1 2 \begin{cases} n_0 + n_1 + n_2 = 2n \\ n_0 = n_2 + 1 \end{cases} \implies 2n_0 + n_1 - 1 = 2n \implies n_0 = n + \frac{1-n_1}{2} {n0+n1+n2=2nn0=n2+1⟹2n0+n1−1=2n⟹n0=n+21−n1
∵ n 1 = 0 \because n_1 = 0 ∵n1=0 或 1 1 1, ∴ n 0 = n + 1 2 \therefore n_0 = n + \frac{1}{2} ∴n0=n+21 或 n 0 = n n_0 = n n0=n
又 ∵ n 0 ∈ Z \because n_0 \in \mathbb{Z} ∵n0∈Z, ∴ n 0 = n \therefore n_0 = n ∴n0=n
(对应两种结构: n 1 = 1 n_1=1 n1=1 或 n 1 = 0 n_1=0 n1=0)
3. 遍历方式
(1)概述
- 前序遍历(先根遍历):根 → 左子树 → 右子树
- 中序遍历(中根遍历):左子树 → 根 → 右子树
- 后序遍历(后根遍历):左子树 → 右子树 → 根
- 层序遍历:一层一层遍历,核心思想:上层带下层
(2)代码实现
这段代码定义了二叉树最基础的节点结构 ,并实现了前、中、后三种递归遍历,是二叉树代码的核心模板。
java
public class BinaryTree1 {
static class TreeNode {
public char val; // 节点存储的值
public TreeNode left; // 左孩子引用
public TreeNode right; // 右孩子引用
public TreeNode(char val) {
this.val = val;
}
}
// 前序遍历:先访问根,再访问左子树,最后访问右子树
public void preOrder(TreeNode root) {
if (root == null) {
return;
}
System.out.print(root.val + " ");
preOrder(root.left);
preOrder(root.right);
}
// 中序遍历:先访问左子树,再访问根,最后访问右子树
public void inOrder(TreeNode root) {
if (root == null) {
return;
}
inOrder(root.left);
System.out.print(root.val + " ");
inOrder(root.right);
}
// 后序遍历:先访问左子树,再访问右子树,最后访问根
public void postOrder(TreeNode root) {
if (root == null) {
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val + " ");
}
}
4. 基本操作实现
这部分代码实现了二叉树最常用的基础功能,包括统计节点数、叶子数、树高度、查找节点、层序遍历。
① 统计节点、叶子节点、第k层节点、树高度
java
public class BinaryTree2 {
// 获取树中结点的个数(思路1:全局变量统计)
public static int nodeSize = 0;
public void size(TreeNode root) {
if (root == null) {
return;
}
nodeSize++;
size(root.left);
size(root.right);
}
// 获取树中结点个数(思路2:递归返回值统计,推荐)
public int size2(TreeNode root) {
if (root == null) {
return 0;
}
// 左子树节点数 + 右子树节点数 + 自己
return size2(root.left) + size2(root.right) + 1;
}
// 获取叶子节点的个数(思路1:全局变量统计)
public static int leafSize;
public void getLeafNodeCount(TreeNode root) {
if (root == null) {
return;
}
// 左右孩子都为空,就是叶子节点
if (root.left == null && root.right == null) {
leafSize++;
}
getLeafNodeCount(root.left);
getLeafNodeCount(root.right);
}
// 获取叶子节点的个数(思路2:递归返回统计,推荐)
public int getLeafNodeCount2(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);
}
// 获取第k层节点的个数
public int getKLevelNodeCount(TreeNode root, int k) {
if (root == null) {
return 0;
}
// 递归到第一层,返回1
if (k == 1) {
return 1;
}
// 左右子树的第k-1层之和
return getKLevelNodeCount(root.left, k-1) + getKLevelNodeCount(root.right, k-1);
}
// 获取二叉树的高度
public int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
// 取左右子树最大高度 + 1(当前层)
return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
}
② 查找指定值的节点
java
// 判断值为value的元素是否存在,存在则返回该节点
public TreeNode findVal(TreeNode root, char val) {
if (root == null) {
return null;
}
// 当前节点就是目标节点
if (root.val == val) {
return root;
}
// 先去左子树查找
TreeNode left = findVal(root.left, val);
if (left != null) {
return left;
}
// 左子树没找到,再去右子树查找
TreeNode right = findVal(root.right, val);
if (right != null) {
return right;
}
// 都没找到
return null;
}
③ 层序遍历
层序遍历使用队列实现,遵循"先进先出",一层一层遍历节点。
java
// 层序遍历:从上到下、从左到右一层一层访问
public void levelOrder(TreeNode root) {
if (root == null) {
return;
}
Deque<TreeNode> deque = new LinkedList<>();
TreeNode cur = root;
deque.offer(root);
while (!deque.isEmpty()) {
cur = deque.poll();
// 访问当前节点
System.out.print(cur.val + " ");
// 左孩子入队
if (cur.left != null) {
deque.offer(cur.left);
}
// 右孩子入队
if (cur.right != null) {
deque.offer(cur.right);
}
}
}
🎯 核心考点总结
- 树是递归结构,n 个节点 ⇒ n-1 条边
- 二叉树最多 两个孩子,严格区分左右
- 满二叉树:每层全满,节点数 2 h − 1 2^h-1 2h−1
- 完全二叉树:前 h-1 层满,最后一层靠左连续
- 必考公式: n 0 = n 2 + 1 n_0 = n_2 + 1 n0=n2+1
- 四种遍历:前、中、后、层序
- 高频操作:节点数、叶子数、高度、第 k 层、查找、层序
✍️ 写在最后
本文是二叉树系列第一篇 ,从最基础的树形结构讲起,完整覆盖概念、性质、公式、递归遍历、基础操作。
这些内容是学习二叉树最核心的地基,也是面试、笔试、竞赛中出现频率极高的基础考点。
扎实掌握本文内容,后续学习平衡二叉树、堆、二叉搜索树等内容会更加轻松。
下一篇内容:
二叉树非递归遍历、翻转二叉树、对称二叉树、路径总和、层序遍历强化题。