一、二叉树基础概念
1. 定义
- 每个节点最多两个孩子:左孩子、右孩子
- 分:空树、只有根、只有左子树、只有右子树、左右都有
2. 基本名词
- 根节点:最上面那个
- 叶子节点:没有孩子的节点
- 父节点、子节点、兄弟节点
- 子树:以某个孩子为根的树
- 深度 / 高度 :
- 深度:从根往下数第几层
- 高度:从当前节点到最远叶子的层数
3. 重要公式
- 第 i 层最多:2i−1 个节点
- 高度 h 的满二叉树最多:2h−1 个节点
- n 个节点的二叉树高度至少:⌊log2n⌋+1
二、二叉树两种存储结构
1. 链式存储(最通用)
struct Node {
int val;
Node *l, *r;
Node(int x) : val(x), l(0), r(0) {}
};
2. 数组存储(完全二叉树专用)
-
根:1
-
i 的左孩子:
2*i -
i 的右孩子:
2*i+1 -
i 的父亲:
i/2int tree[100005];
三、二叉树四大遍历(必考核心)
1. 前序:根 → 左 → 右
void pre(Node *u) {
if (!u) return;
cout << u->val;
pre(u->l);
pre(u->r);
}
2. 中序:左 → 根 → 右
void in(Node *u) {
if (!u) return;
in(u->l);
cout << u->val;
in(u->r);
}
3. 后序:左 → 右 → 根
void post(Node *u) {
if (!u) return;
post(u->l);
post(u->r);
cout << u->val;
}
4. 层序:按层遍历(BFS)
void bfs(Node *root) {
queue<Node*> q;
q.push(root);
while (!q.empty()) {
Node *u = q.front(); q.pop();
cout << u->val;
if (u->l) q.push(u->l);
if (u->r) q.push(u->r);
}
}
四、必考结论
- 前序 + 中序 可确定二叉树
- 后序 + 中序 可确定二叉树
- 前序 + 后序 不能唯一确定
五、特殊二叉树(完整体系)
1. 满二叉树
- 所有非叶子都有 2 个孩子
- 所有叶子在同一层
2. 完全二叉树
- 除最后一层,前面全满
- 最后一层靠左排列
- 用途:堆、线段树
3. 二叉搜索树 BST
规则:左 < 根 < 右
- 中序遍历 = 有序序列
- 查找、插入、删除平均 O (log n)
- 最坏退化成链 O (n)
4. 平衡二叉树 AVL
- BST + 左右高度差 ≤ 1
- 不平衡靠旋转修正
- 保证稳定 O (log n)
5. 红黑树
- 弱平衡 BST,节点带颜色
- 最长路径 ≤ 最短路径 × 2
- C++
map/set底层
6. 堆(完全二叉树)
- 大根堆:父 ≥ 子
- 小根堆:父 ≤ 子
- 用途:优先队列、Dijkstra、堆排序
7. 哈夫曼树(最优二叉树)
- 带权路径长度 WPL 最小
- 权大靠近根,权小在深处
- 用途:哈夫曼编码、数据压缩
8. 线索二叉树
- 把空指针利用:
- 左空 → 前驱
- 右空 → 后继
- 非递归遍历更快
六、基础操作(递归万能)
1. 求树深度
int dfs(Node *u) {
if (!u) return 0;
return max(dfs(u->l), dfs(u->r)) + 1;
}
2. 求节点总数
int cnt(Node *u) {
if (!u) return 0;
return cnt(u->l) + cnt(u->r) + 1;
}
3. 求叶子数
int leaf(Node *u) {
if (!u) return 0;
if (!u->l && !u->r) return 1;
return leaf(u->l) + leaf(u->r);
}
七、洛谷经典真题(直接能交)
题 1:P1030 已知中序后序求前序
#include <iostream>
#include <string>
using namespace std;
string in, post;
void dfs(int l1, int r1, int l2, int r2) {
if (l1 > r1) return;
char root = post[r2];
cout << root;
int k = l1;
while (in[k] != root) k++;
int len = k - l1;
dfs(l1, k-1, l2, l2+len-1);
dfs(k+1, r1, l2+len, r2-1);
}
int main() {
cin >> in >> post;
dfs(0, in.size()-1, 0, post.size()-1);
return 0;
}
题 2:P3378 小根堆模板
#include <iostream>
using namespace std;
int h[1000005], len;
void up(int i) {
while (i>1 && h[i]<h[i/2]) {
swap(h[i], h[i/2]);
i /= 2;
}
}
void down(int i) {
int s;
while (2*i <= len) {
s = 2*i;
if (s+1 <= len && h[s+1]<h[s]) s++;
if (h[s] < h[i]) swap(h[i], h[s]), i=s;
else break;
}
}
void push(int x) { h[++len]=x; up(len); }
void pop() { h[1]=h[len--]; down(1); }
int main() {
int n, op, x;
cin >> n;
while (n--) {
cin >> op;
if (op == 1) cin >> x, push(x);
else if (op == 2) cout << h[1] << '\n';
else pop();
}
return 0;
}
题 3:P1090 合并果子(哈夫曼)
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int, vector<int>, greater<int>> q;
int main() {
int n, x, ans=0;
cin >> n;
while (n--) cin >> x, q.push(x);
while (q.size()>1) {
int a=q.top(); q.pop();
int b=q.top(); q.pop();
ans += a+b;
q.push(a+b);
}
cout << ans;
return 0;
}
八、完整二叉树知识体系总结
- 基础概念 + 存储
- 4 种遍历(前中后层)
- 递归万能操作(深度、数量、叶子)
- 8 种特殊二叉树
- 3 道洛谷经典题(可直接 AC)