一、什么是二叉树(Binary Tree)
定义:
二叉树是一种树形结构,其中每个节点最多有两个子节点,分别称为左子节点(left child)和右子节点(right child)。
每个节点最多有 2 个分支,这两个分支可以为空。
例子
A
/ \
B C
/ \ \
D E F
- A 是根节点(Root)
- B、C 是 A 的孩子(Child)
- D、E、F 是叶子节点(Leaf)
- B 的父节点是 A
- D 的兄弟节点是 E
二、二叉树的基本术语
| 名称 | 含义 |
|---|---|
| 根节点(Root) | 没有父节点的节点 |
| 叶子节点(Leaf) | 没有子节点的节点 |
| 父节点(Parent) | 有子节点的节点 |
| 子节点(Child) | 父节点的下属节点 |
| 兄弟节点(Sibling) | 具有相同父节点的节点 |
| 节点深度(Depth) | 从根到该节点的边数 |
| 节点高度(Height) | 从该节点到叶子的最长路径 |
| 层级(Level) | 节点的深度 + 1 |
| 满二叉树(Full Binary Tree) | 所有非叶子节点都有两个子节点 |
| 完全二叉树(Complete Binary Tree) | 除最后一层外,其他层节点全满,最后一层从左到右依次填充 |
三、二叉树的分类
| 类型 | 定义 |
|---|---|
| 普通二叉树 | 任意结构 |
| 满二叉树 | 所有非叶节点都有两个孩子,叶子都在同一层 |
| 完全二叉树 | 除最后一层外全满,最后一层从左向右填充 |
| 二叉搜索树(BST) | 左子树 < 根 < 右子树 |
| 平衡二叉树(AVL Tree) | 左右子树高度差 ≤ 1 |
| 红黑树(Red-Black Tree) | 一种自平衡二叉搜索树 |
| 线索二叉树(Threaded Binary Tree) | 用空指针指向前驱/后继节点以加速遍历 |
四、二叉树的性质
设二叉树中第 i i i 层最多有 2 i − 1 2^{i-1} 2i−1 个节点:
-
第 i i i 层最多节点数:
N i = 2 i − 1 N_i = 2^{i-1} Ni=2i−1 -
深度为 k k k 的二叉树最多节点数:
N max = 2 k − 1 N_{\max} = 2^k - 1 Nmax=2k−1 -
具有 n n n 个节点的二叉树,高度至少为:
h min = ⌈ log 2 ( n + 1 ) ⌉ h_{\min} = \lceil \log_2(n + 1) \rceil hmin=⌈log2(n+1)⌉ -
若叶子节点数为 n 0 n_0 n0,度为 2 的节点数为 n 2 n_2 n2,则:
n 0 = n 2 + 1 n_0 = n_2 + 1 n0=n2+1
五、二叉树的存储方式
1.顺序存储(数组存储)
适用于 完全二叉树
设根节点下标为 1,则:
- 左孩子:
2*i - 右孩子:
2*i + 1 - 父节点:
i / 2
例如:
A(1)
/ \
B(2) C(3)
/ \ /
D(4) E(5) F(6)
数组存储:
[ _, A, B, C, D, E, F ]
2.链式存储(指针结构)
cpp
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
每个节点保存两个指针,分别指向左、右子节点。
六、二叉树的遍历(Traversal)
遍历是访问二叉树所有节点的过程。
1.深度优先遍历(DFS)
-
前序遍历(Preorder) :根 → 左 → 右
顺序:Root, Left, Right
-
中序遍历(Inorder) :左 → 根 → 右
顺序:Left, Root, Right
-
后序遍历(Postorder) :左 → 右 → 根
顺序:Left, Right, Root
示例
A
/ \
B C
/ \ \
D E F
| 遍历类型 | 结果顺序 |
|---|---|
| 前序 | A B D E C F |
| 中序 | D B E A C F |
| 后序 | D E B F C A |
递归实现(以中序为例)
cpp
void inorder(TreeNode* root) {
if (!root) return;
inorder(root->left);
cout << root->val << " ";
inorder(root->right);
}
2.广度优先遍历(BFS)
即 层序遍历(Level Order Traversal)
利用队列(Queue)实现。
cpp
void levelOrder(TreeNode* root) {
if (!root) return;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front(); q.pop();
cout << node->val << " ";
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
结果:
A B C D E F
七、二叉树的应用
| 应用场景 | 示例 |
|---|---|
| 表达式解析树 | 编译器、计算器((a+b)*c) |
| 二叉搜索树 BST | 查找、排序 |
| 堆(Heap) | 优先队列(最小堆、最大堆) |
| 哈夫曼树(Huffman Tree) | 数据压缩 |
| 决策树(Decision Tree) | 机器学习 |
| KD 树 / Octree | 空间索引与点云处理 |
八、构建与销毁
cpp
TreeNode* buildTree() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);
return root;
}
void destroy(TreeNode* root) {
if (!root) return;
destroy(root->left);
destroy(root->right);
delete root;
}
九、复杂度与性能
| 操作 | 平均复杂度 | 最坏情况 |
|---|---|---|
| 插入 | O ( log n ) O(\log n) O(logn) | O ( n ) O(n) O(n)(链化) |
| 删除 | O ( log n ) O(\log n) O(logn) | O ( n ) O(n) O(n) |
| 查找 | O ( log n ) O(\log n) O(logn) | O ( n ) O(n) O(n) |
| 遍历 | O ( n ) O(n) O(n) | O ( n ) O(n) O(n) |
为避免退化,可使用 AVL Tree 或 Red-Black Tree。
十、总结表
| 分类 | 特点 | 示例 |
|---|---|---|
| 普通二叉树 | 任意结构 | 一般树结构 |
| 满二叉树 | 每个非叶子都有两个孩子 | 理论分析 |
| 完全二叉树 | 从左至右填满 | 堆 |
| 二叉搜索树 | 左 < 根 < 右 | 查找树 |
| 平衡树 | 高度差≤1 | AVL、红黑树 |
| 线索树 | 空指针指向前驱/后继 | 遍历优化 |
十一、 综合示例-二叉搜索树(BST)
下面实现l一个完整的 Binary Search Tree 类,包括:
- 节点定义
- 插入节点
- 查找节点
- 删除节点
- 三种深度优先遍历(前序 / 中序 / 后序)
- 层序遍历
- 销毁树
1.数据结构定义
cpp
#include <iostream>
#include <queue>
using namespace std;
// 二叉树节点定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
2.二叉搜索树类定义
cpp
class BinarySearchTree {
private:
TreeNode* root;
// 插入节点(递归)
TreeNode* insert(TreeNode* node, int val) {
if (!node) return new TreeNode(val);
if (val < node->val) node->left = insert(node->left, val);
else if (val > node->val) node->right = insert(node->right, val);
return node;
}
// 查找节点(递归)
bool search(TreeNode* node, int val) {
if (!node) return false;
if (val == node->val) return true;
else if (val < node->val) return search(node->left, val);
else return search(node->right, val);
}
// 找到最小值节点
TreeNode* findMin(TreeNode* node) {
while (node->left) node = node->left;
return node;
}
// 删除节点
TreeNode* remove(TreeNode* node, int val) {
if (!node) return nullptr;
if (val < node->val) node->left = remove(node->left, val);
else if (val > node->val) node->right = remove(node->right, val);
else {
// 情况 1:无子节点
if (!node->left && !node->right) {
delete node;
return nullptr;
}
// 情况 2:只有一个子节点
else if (!node->left) {
TreeNode* temp = node->right;
delete node;
return temp;
} else if (!node->right) {
TreeNode* temp = node->left;
delete node;
return temp;
}
// 情况 3:有两个子节点
else {
TreeNode* minNode = findMin(node->right);
node->val = minNode->val;
node->right = remove(node->right, minNode->val);
}
}
return node;
}
// 遍历函数
void preorder(TreeNode* node) {
if (!node) return;
cout << node->val << " ";
preorder(node->left);
preorder(node->right);
}
void inorder(TreeNode* node) {
if (!node) return;
inorder(node->left);
cout << node->val << " ";
inorder(node->right);
}
void postorder(TreeNode* node) {
if (!node) return;
postorder(node->left);
postorder(node->right);
cout << node->val << " ";
}
// 销毁整棵树
void destroy(TreeNode* node) {
if (!node) return;
destroy(node->left);
destroy(node->right);
delete node;
}
public:
BinarySearchTree() : root(nullptr) {}
~BinarySearchTree() { destroy(root); }
void insert(int val) { root = insert(root, val); }
void remove(int val) { root = remove(root, val); }
bool search(int val) { return search(root, val); }
// 层序遍历
void levelOrder() {
if (!root) return;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
TreeNode* node = q.front(); q.pop();
cout << node->val << " ";
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
// 打印不同遍历结果
void printOrders() {
cout << "Preorder: "; preorder(root); cout << "\n";
cout << "Inorder: "; inorder(root); cout << "\n";
cout << "Postorder: "; postorder(root); cout << "\n";
cout << "Level order: "; levelOrder(); cout << "\n";
}
};
3.主程序示例
cpp
int main() {
BinarySearchTree bst;
// 插入节点
bst.insert(50);
bst.insert(30);
bst.insert(70);
bst.insert(20);
bst.insert(40);
bst.insert(60);
bst.insert(80);
cout << "Binary Search Tree traversals:\n";
bst.printOrders();
cout << "\nSearch for 60: " << (bst.search(60) ? "Found" : "Not Found") << "\n";
cout << "\nRemove 70\n";
bst.remove(70);
cout << "After deletion:\n";
bst.printOrders();
return 0;
}
输出结果
Binary Search Tree traversals:
Preorder: 50 30 20 40 70 60 80
Inorder: 20 30 40 50 60 70 80
Postorder: 20 40 30 60 80 70 50
Level order: 50 30 70 20 40 60 80
Search for 60: Found
Remove 70
After deletion:
Preorder: 50 30 20 40 80 60
Inorder: 20 30 40 50 60 80
Postorder: 20 40 30 60 80 50
Level order: 50 30 80 20 40 60
示例分析
| 操作 | 说明 |
|---|---|
| 插入 | 构建一棵 BST,左小右大 |
| 查找 | 二分性质快速定位 |
| 删除 | 三种情况(无子、单子、双子) |
| 遍历 | 四种遍历全面展示树结构 |
| 销毁 | 递归释放所有节点,避免内存泄漏 |