前言
二叉树是计算机科学中最基础的树形数据结构之一,在数据库索引、文件系统等领域广泛应用。本文通过C语言实现包含插入、遍历等基本操作的二叉树,特别针对初学者设计,包含完整代码注释和遍历过程图解。
一、二叉树基础知识
核心特性:
-
每个节点最多有两个子节点(左/右子节点)
-
特殊的树结构:二叉搜索树、平衡二叉树、满二叉树等
-
常用遍历方式:广度优先(BFS)、深度优先(DFS)
二、代码结构解析
1. 节点结构定义
c
typedef struct Node { int key; // 节点存储的值 struct Node* lchild; // 左子节点指针 struct Node* rchild; // 右子节点指针 } Node;
内存结构:
+--------+--------+--------+ | key | lchild | rchild | +--------+--------+--------+
2. 节点创建函数
c
Node* getNewNode(int key) { Node* p = (Node*)malloc(sizeof(Node)); p->key = key; // 设置节点值 p->lchild = p->rchild = NULL; // 初始化子节点指针 return p; }
关键点:
-
使用
malloc
动态分配内存 -
初始化时将子节点指针置为NULL
3. 插入操作(随机插入)
c
Node* insert(Node* root, int key) { if (root == NULL) return getNewNode(key); // 空树创建新节点 // 随机选择插入方向(50%概率左右) if (rand() % 2) root->lchild = insert(root->lchild, key); else root->rchild = insert(root->rchild, key); return root; }
插入逻辑:
-
如果当前节点为空,创建新节点
-
通过随机数决定插入左/右子树
-
递归完成插入操作
4. 内存释放(后序遍历)
c
void clear(Node* root) { if (root == NULL) return; clear(root->lchild); // 先释放左子树 clear(root->rchild); // 再释放右子树 free(root); // 最后释放当前节点 }
释放顺序:
必须先释放子节点再释放父节点,避免访问已释放内存
三、遍历算法实现
1. 广度优先搜索(BFS)
c
#define MAX_NODE 10 Node* queue[MAX_NODE + 5]; // 循环队列 int head, tail; void bfs(Node* root) { head = tail = 0; queue[tail++] = root; // 根节点入队 while (head < tail) { Node* node = queue[head++]; // 取出队首节点 printf("\nnode : %d\n", node->key); if (node->lchild) { // 左子节点入队 queue[tail++] = node->lchild; printf("\t%d->%d (left)\n", node->key, node->lchild->key); } if (node->rchild) { // 右子节点入队 queue[tail++] = node->rchild; printf("\t%d->%d (right)\n", node->key, node->rchild->key); } } }
执行过程:
队列状态变化: [5] → [5,3] → [3,7] → ... 输出顺序:5 → 3 → 7 → ...
2. 深度优先搜索(DFS)
c
int tot = 0; // 全局计数器 void dfs(Node* root) { if (root == NULL) return; int start = ++tot; // 进入节点时记录起始位置 if (root->lchild) dfs(root->lchild); // 递归左子树 if (root->rchild) dfs(root->rchild); // 递归右子树 int end = ++tot; // 离开节点时记录结束位置 printf("%d : [%d, %d]\n", root->key, start, end); }
访问顺序:
示例树: 5 / \ 3 7 输出: 3 : [2, 3] 7 : [4, 5] 5 : [1, 6]
四、主函数测试
c
int main() { srand(time(0)); // 初始化随机种子 Node* root = NULL; // 插入10个随机节点 for (int i = 0; i < MAX_NODE; i++) { root = insert(root, rand() % 100); } bfs(root); // 广度优先遍历 dfs(root); // 深度优先遍历 clear(root); // 释放内存 return 0; }
五、运行结果分析
典型BFS输出:
node : 56 56->34 (left) 56->78 (right) node : 34 34->12 (left) node : 78 ...
DFS输出示例:
12 : [2, 3] 34 : [1, 4] 78 : [5, 8] 56 : [1, 9]
六、常见问题解答
-
为什么用随机插入?
-
简化示例代码逻辑
-
实际应用应根据需求选择插入策略(如二叉搜索树)
-
-
DFS中的区间编号有什么意义?
-
模拟树形结构的区间表示法
-
可用于子树范围判断等场景
-
-
如何处理大型二叉树?
-
使用动态队列替代静态数组
-
递归深度过大时可改用迭代实现
-
七、总结与扩展
核心知识点:
-
二叉树节点的链式存储
-
递归在树结构中的应用
-
BFS与DFS的实现差异
扩展方向:
-
实现二叉搜索树
-
添加节点删除功能
-
实现平衡二叉树(AVL树)
相关练习:实现二叉树的高度计算、镜像翻转、路径查找
注:代码出自B站海贼胡船长