一、树的基本概念与核心结构
1.1 树的定义与特性
树是一种非线性数据结构,由节点集合和边集合构成,满足以下条件:
- 根节点:唯一没有父节点的节点。
- 子树:每个节点的子节点形成互不相交的子树。
- 递归性:树可以是空树,或由根节点和若干子树构成。
核心术语:
- 度:节点的子节点数(叶子节点度为0)。
- 深度:根到该节点的路径长度(根深度为1)。
- 高度:节点到最远叶子的路径长度。
- 路径唯一性:任意两节点间有唯一路径。
1.2 树的存储结构
- 双亲表示法(顺序存储):数组存储节点,每个节点记录父节点索引。
- 孩子链表示法(链式存储):每个节点维护子节点指针链表。
- 孩子兄弟表示法(链式存储):节点包含左孩子和右兄弟指针。
二、二叉树的核心理论与性质
2.1 二叉树的定义
二叉树是每个节点最多有两个子节点的树,子树分为左子树和右子树,且顺序不可交换。二叉树可以是空树,或由根节点和左右子树组成。
五种基本形态:空树、仅根节点、左子树、右子树、左右子树均存在。
2.2 二叉树的性质
- 第i层最多有 (2^{i-1}) 个节点。
- 深度为k的二叉树最多有 (2^k - 1) 个节点。
- 叶子节点数 (n_0 = n_2 + 1)((n_2) 为度为2的节点数)。
2.3 特殊二叉树
- 满二叉树:所有层节点数达到最大值。
- 完全二叉树:除最后一层外全满,且最后一层节点左对齐。
- 二叉搜索树(BST):左子树节点值均小于根,右子树节点值均大于根。
三、二叉树的C语言实现
3.1 节点定义与创建
typedef struct TreeNode {
int data;
struct TreeNode* left;
struct TreeNode* right;
} TreeNode;
// 创建新节点
TreeNode* createNode(int data) {
TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
if (newNode == NULL) {
printf("内存分配失败\n");
exit(1);
}
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
3.2 二叉搜索树操作
插入节点
TreeNode* insert(TreeNode* root, int data) {
if (root == NULL) {
root = createNode(data);
} else if (data < root->data) {
root->left = insert(root->left, data); // 递归插入左子树
} else if (data > root->data) {
root->right = insert(root->right, data); // 递归插入右子树
}
return root;
}
查找节点
TreeNode* search(TreeNode* root, int key) {
if (root == NULL || root->data == key) {
return root;
}
if (key < root->data) {
return search(root->left, key);
} else {
return search(root->right, key);
}
}
删除节点
// 辅助函数:找到右子树最小节点
TreeNode* findMin(TreeNode* root) {
while (root->left != NULL) {
root = root->left;
}
return root;
}
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == NULL) return root;
if (key < root->data) {
root->left = deleteNode(root->left, key);
} else if (key > root->data) {
root->right = deleteNode(root->right, key);
} else {
// 情况1:无子节点或一个子节点
if (root->left == NULL) {
TreeNode* temp = root->right;
free(root);
return temp;
} else if (root->right == NULL) {
TreeNode* temp = root->left;
free(root);
return temp;
}
// 情况2:有两个子节点
TreeNode* temp = findMin(root->right);
root->data = temp->data;
root->right = deleteNode(root->right, temp->data);
}
return root;
}
3.3 遍历算法
递归遍历
// 前序遍历:根→左→右
void preOrder(TreeNode* root) {
if (root != NULL) {
printf("%d ", root->data);
preOrder(root->left);
preOrder(root->right);
}
}
// 中序遍历:左→根→右(BST中输出有序序列)
void inOrder(TreeNode* root) {
if (root != NULL) {
inOrder(root->left);
printf("%d ", root->data);
inOrder(root->right);
}
}
// 后序遍历:左→右→根
void postOrder(TreeNode* root) {
if (root != NULL) {
postOrder(root->left);
postOrder(root->right);
printf("%d ", root->data);
}
}
层序遍历(队列实现)
void levelOrder(TreeNode* root) {
if (root == NULL) return;
Queue q;
initQueue(&q);
enqueue(&q, root);
while (!isEmpty(&q)) {
TreeNode* current = dequeue(&q);
printf("%d ", current->data);
if (current->left != NULL) enqueue(&q, current->left);
if (current->right != NULL) enqueue(&q, current->right);
}
}
四、实战案例:构建与操作BST
示例代码
int main() {
TreeNode* root = NULL;
// 插入节点
root = insert(root, 50);
insert(root, 30);
insert(root, 20);
insert(root, 40);
insert(root, 70);
insert(root, 60);
insert(root, 80);
// 中序遍历输出有序序列
printf("中序遍历:");
inOrder(root); // 输出:20 30 40 50 60 70 80
// 删除节点
root = deleteNode(root, 20);
printf("\n删除20后的中序遍历:");
inOrder(root); // 输出:30 40 50 60 70 80
// 释放内存
freeTree(root);
return 0;
}
内存释放
void freeTree(TreeNode* root) {
if (root == NULL) return;
freeTree(root->left);
freeTree(root->right);
free(root);
root = NULL;
}
五、总结
- 树的应用场景:文件系统、数据库索引、哈夫曼编码等。
- 二叉搜索树的优势:查找、插入、删除操作的时间复杂度为 (O(\log n))(平衡时)。
- C语言实现要点:递归逻辑、指针操作、动态内存管理。
-
参考资料:
- 树与二叉树的C语言实现方法
- 二叉树的性质与分类
- 二叉查找树的插入与删除操作
- 遍历算法的递归与非递归实现
- 树的基本术语与存储结构
- 完全二叉树与满二叉树的区别