

🔥个人主页:北极的代码(欢迎来访)
🎬作者简介:java后端学习者
✨命运的结局尽可永在,不屈的挑战却不可须臾或缺!
前言:
我们继续学习《数据结构与算法》,前面我们学习了栈和队列,这里我们先对二叉树基本知识点进行大体的了解,然后我们后续会在算法题中进行应用。
本文摘要:
深入浅出讲解二叉树核心知识,包括存储方式(链式/顺序)、遍历方法(前序/中序/后序/层序)和分类(满二叉树/完全二叉树/BST等)。
重点解析三种深度优先遍历的特点:前序(根左右)适合复制操作,中序(左根右)天然有序,后序(左右根)适用删除场景。
文章对比了各类二叉树的时间复杂度,推荐优先掌握普通二叉树和BST,并介绍了Java中TreeMap(红黑树)、PriorityQueue(堆)等实现。
通过生活化类比(如文件夹操作)帮助理解遍历逻辑,为后续算法学习奠定基础。
二叉树的存储方式
二叉树可以链式存储,也可以顺序存储。
那么链式存储方式就用指针, 顺序存储的方式就是用数组。
当然这个定义是针对C语言的,毕竟java中并没有指针这个概念,java中链式存储用的是引用来来连接节点。
顾名思义就是顺序存储的元素在内存是连续分布的,而链式存储则是通过指针把分布在各个地址的节点串联一起。
链式存储如图:
链式存储是大家很熟悉的一种方式,那么我们来看看如何顺序存储呢
顺序存储如图:
其实就是用数组来存储二叉树:
用数组来存储二叉树如何遍历的呢
如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
但是用链式表示的二叉树,更有利于我们理解,所以一般我们都是用链式存储二叉树。
但大家要了解,用数组依然可以表示二叉树。
二叉树的遍历方式
关于二叉树的遍历方式,要知道二叉树遍历的基本方式都有哪些。
我们这里把二叉树的几种遍历方式列出来,大家就可以一一串起来。
二叉树主要有两种遍历方式:
- 深度优先遍历:先往深走,遇到叶子节点再往回走。
- 广度优先遍历:一层一层的去遍历。
这两种遍历是图论中最基本的两种遍历方式,后面在介绍图论的时候 还会介绍到。
那么从深度优先遍历和广度优先遍历进一步拓展,才有如下遍历方式:
- 深度优先遍历
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
- 广度优先遍历
- 层次遍历(迭代法)
在深度优先遍历中:有三个顺序,前中后序遍历, 我们有时候总分不清这三个顺序,经常搞混,我这里教大家一个技巧。
这里前中后,其实指的就是中间节点的遍历顺序,只要大家记住 前中后序指的就是中间节点的位置就可以了。
看如下中间节点的顺序,就可以发现,中间节点的顺序就是所谓的遍历方式
- 前序遍历:中左右
- 中序遍历:左中右
- 后序遍历:左右中
前序遍历:
先记自己,再找左边,最后找右边
你每到一个房间(节点):
立刻在笔记本上记下这个房间的名字(记录根)
然后先去左边所有的房间(遍历左子树)
左边全部走完后,再去右边所有的房间(遍历右子树)
就像你去拜访一个家族:进门先喊自己的名字,再去找左边的亲戚,最后找右边的亲戚
口诀:根 → 左 → 右
生活例子:复制文件夹
你复制一个文件夹时,总是先创建当前文件夹,再复制里面的子文件夹
这就是典型的前序思路
中序遍历:
先找最左边,再记自己,最后找右边
你每到一个房间:
先不急着记录,先看看左边还有没有房间
一直往左边走,直到没有左边房间了
记录当前节点
然后再去右边房间,右边房间同样重复:先找最左边
就像你走进一个图书馆,你总是先走到最左边的那一排书架,然后开始记录,记录完一个就往右边移
口诀:左 → 根 → 右
生活例子:BST排序输出
二叉搜索树用中序遍历,出来的结果就是从小到大排好序的
就像你按身高排队报数,矮的先报
后序遍历:
先找左边,再找右边,最后记自己
你每到一个房间:
先把左边所有房间走完,记录完
再把右边所有房间走完,记录完
最后才记录当前房间
就像你清理房间:先把两个小房间都打扫干净,最后才打扫中间的大客厅
口诀:左 → 右 → 根
生活例子:删除文件夹
你要删除一个文件夹,必须先删除里面的所有子文件夹和文件(先删子节点),最后删除自己
这就是后序思路
假设有这样一棵树:
text
根 / \ A B / \ \ C D E手动模拟(记住A的左是C和D,B的右是E):
遍历 访问顺序 解释 前序 根 → A → C → D → B → E 每到一节点立刻输出 中序 C → A → D → 根 → B → E 一直往左到底才输出 后序 C → D → A → E → B → 根 子节点处理完才输出父节点 最后再说一说二叉树中深度优先和广度优先遍历实现方式,我们做二叉树相关题目,经常会使用递归的方式来实现深度优先遍历,也就是实现前中后序遍历,使用递归是比较方便的。
之前我们讲栈与队列的时候,就说过栈其实就是递归的一种实现结构 ,也就说前中后序遍历的逻辑其实都是可以借助栈使用递归的方式来实现的。
而广度优先遍历的实现一般使用队列来实现,这也是队列先进先出的特点所决定的,因为需要先进先出的结构,才能一层一层的来遍历二叉树。
这里其实我们又了解了栈与队列的一个应用场景了。
具体的实现我们后面都会讲的,这里大家先要清楚这些理论基础。
二叉树的定义
刚刚我们说过了二叉树有两种存储方式顺序存储,和链式存储,顺序存储就是用数组来存,这个定义没啥可说的,我们来看看链式存储的二叉树节点的定义方式。
C++代码如下:
struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} };java代码
public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() {} TreeNode(int val) { this.val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this.val = val; this.left = left; this.right = right; } }大家会发现二叉树的定义 和链表是差不多的,相对于链表 ,二叉树的节点里多了一个指针, 有两个指针,指向左右孩子。
这里要提醒大家要注意二叉树节点定义的书写方式。
在现场面试的时候 面试官可能要求手写代码,所以数据结构的定义以及简单逻辑的代码一定要锻炼白纸写出来。
因为我们在刷leetcode的时候,节点的定义默认都定义好了,真到面试的时候,可能需要自己写节点定义
二叉树的分类:
按逻辑结构分类
| 种类 | 特点 | 典型应用 |
|---|---|---|
| 满二叉树 | 每个节点要么是叶子,要么有两个子节点,所有叶子在同一层 | 堆排序的完全二叉树特例 |
| 完全二叉树 | 除最后一层外全满,最后一层节点左对齐 | 二叉堆、优先队列 |
| 平衡二叉树 | 任意节点左右子树高度差 ≤ 1 | AVL树、红黑树 |
| 二叉搜索树(BST) | 左子树 < 根 < 右子树 | 快速查找、插入、删除 |
| 斜树 | 所有节点只有左孩子(左斜树)或只有右孩子(右斜树) | 退化成了链表(最坏情况) |
按平衡机制分类
(Java中常用的自平衡树)
1. AVL树
特点:严格平衡,高度差 ≤ 1
优点:查询极快
缺点:插入/删除需要频繁旋转
Java中没有直接实现,但可以自己写
2. 红黑树
特点:近似平衡,通过颜色标记和旋转维持平衡
优点:插入/删除比AVL快,查询也很快
Java中的实现:
TreeMap(底层是红黑树)
TreeSet(底层是红黑树)
HashMap的链表转红黑树(当链表长度 ≥ 8 时)
javajava // TreeMap 底层是红黑树 TreeMap<Integer, String> map = new TreeMap<>(); // TreeSet 底层也是红黑树 TreeSet<Integer> set = new TreeSet<>();
按实现方式分类
(Java集合框架中的树)
| 种类 | Java实现类 | 底层结构 | 特点 |
|---|---|---|---|
| 红黑树 | TreeMap、TreeSet |
红黑树 | 有序,不允许null键(TreeMap) |
| 二叉堆 | PriorityQueue |
完全二叉树(数组实现) | 优先级队列,堆顶最值 |
| 字典树 | 无标准库,需自己实现 | 多叉树变种 | 高效字符串前缀匹配 |
特殊用途的二叉树
1. 二叉堆(PriorityQueue底层)
逻辑上:完全二叉树
物理上:用数组存储
性质:父节点 ≥ 子节点(大顶堆)或 ≤ 子节点(小顶堆)
javajava // Java中的优先队列(小顶堆) PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // 大顶堆 PriorityQueue<Integer> maxHeap = new PriorityQueue<>((a, b) -> b - a);2. 线段树
特点:每个节点代表一个区间
应用:区间求和、区间最值、区间修改
Java中无现成实现,需手写
3. 字典树(Trie)
特点:字符串树,共享公共前缀
应用:自动补全、词频统计、敏感词过滤
Java中无标准实现,需手写
4. 二叉线索树
特点:利用空指针指向遍历前驱/后继
优点:节省空间,便于遍历
Java中很少直接用,但Morris遍历用了这个思想
需要重点掌握的
| 学习优先级 | 种类 | 理由 |
|---|---|---|
| 夯 | 普通二叉树 | 刷题基础,所有树的基础 |
| 夯 | 二叉搜索树(BST) | 算法题高频,理解查找/插入/删除 |
| 人上人 | 完全二叉树 | 堆的基础,PriorityQueue原理 |
| 顶级 | 平衡二叉树 | 理解TreeMap/TreeSet原理 |
| 夯 | 红黑树 | 面试常问,但不需要手写 |
| 拉完了 | 线段树/Trie | 特定场景使用 |
总结对比
| 种类 | 有序性 | 平衡性 | 查询复杂度 | Java中的代表 |
|---|---|---|---|---|
| 普通二叉树 | 无 | 不一定 | O(n) | 自己定义TreeNode |
| 二叉搜索树 | 有 | 不一定 | O(n)最坏 | 无标准实现 |
| AVL树 | 有 | 严格 | O(log n) | 需手写 |
| 红黑树 | 有 | 近似 | O(log n) | TreeMap/TreeSet |
| 二叉堆 | 部分(只有最值) | 完全 | O(1)取最值 | PriorityQueue |
一句话记忆
刷题用普通二叉树和BST,理解有序用TreeMap,实现优先级队列用PriorityQueue(完全二叉树),面试问平衡就答红黑树。
目前刷题阶段,重点关注普通二叉树 和二叉搜索树即可,红黑树先理解概念,不需要手写实现。
结语:如果对你有帮助,请**点赞,关注,收藏,**你的支持就是我最大的鼓励!

