一、前言
二叉搜索树(BST,Binary Search Tree)是数据结构中最基础、面试最常考的树形结构。
本文使用 C语言 + 递归 完整实现二叉搜索树所有核心功能:
-
节点创建
-
节点插入
-
节点查找
-
最小值查找
-
节点删除(三大删除情况全覆盖)
-
前序/中序/后序遍历
-
整树内存释放
代码可直接编译运行,注释极其详细,适合新手学习、期末作业、面试复习。
二、二叉搜索树核心性质
二叉搜索树必须满足以下规则:
-
左子树所有节点值 小于 根节点值
-
右子树所有节点值 大于 根节点值
-
左右子树也必须是二叉搜索树
-
BST 不允许存储重复数据
-
中序遍历结果一定是升序序列(BST 最重要特性)
三、完整可运行代码
cpp
#include <stdio.h>
#include <stdlib.h>
// 定义二叉搜索树的节点结构
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(EXIT_FAILURE);
}
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
return newNode;
}
// 递归插入节点
TreeNode* insert(TreeNode* root, int data) {
// 空树位置,创建新节点
if (root == NULL) {
return createNode(data);
}
// 比根小插左边
if (data < root->data) {
root->left = insert(root->left, data);
}
// 比根大插右边
else if (data > root->data) {
root->right = insert(root->right, data);
}
// 相等不处理(BST无重复节点)
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);
}
// 大于当前节点,往右找
return search(root->right, key);
}
// 查找以root为根的树的最小值(最左节点)
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;
}
// 情况2:无右孩子
else if (root->right == NULL) {
TreeNode* temp = root->left;
free(root);
return temp;
}
// 情况3:左右孩子都存在
// 用右子树最小值替换当前节点,再删除最小值节点
TreeNode* temp = findMin(root->right);
root->data = temp->data;
root->right = deleteNode(root->right, temp->data);
}
return root;
}
// 中序遍历:左-根-右(升序)
void inorderTraversal(TreeNode* root) {
if (root != NULL) {
inorderTraversal(root->left);
printf("%d ", root->data);
inorderTraversal(root->right);
}
}
// 前序遍历:根-左-右
void preorderTraversal(TreeNode* root) {
if (root != NULL) {
printf("%d ", root->data);
preorderTraversal(root->left);
preorderTraversal(root->right);
}
}
// 后序遍历:左-右-根
void postorderTraversal(TreeNode* root) {
if (root != NULL) {
postorderTraversal(root->left);
postorderTraversal(root->right);
printf("%d ", root->data);
}
}
// 递归销毁整棵树,释放内存
void destroyTree(TreeNode* root) {
if (root != NULL) {
destroyTree(root->left);
destroyTree(root->right);
free(root);
}
}
// 主函数测试
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("中序遍历(升序): ");
inorderTraversal(root);
printf("\n");
printf("前序遍历: ");
preorderTraversal(root);
printf("\n");
printf("后序遍历: ");
postorderTraversal(root);
printf("\n");
// 查找测试
TreeNode* found = search(root, 60);
if (found) {
printf("成功找到节点: %d\n", found->data);
} else {
printf("未找到该节点\n");
}
// 删除节点测试
root = deleteNode(root, 30);
printf("删除节点30后【中序遍历】: ");
inorderTraversal(root);
printf("\n");
// 释放内存
destroyTree(root);
return 0;
}
四、运行结果
编译运行后输出如下:
cpp
中序遍历(升序): 20 30 40 50 60 70 80
前序遍历: 50 30 20 40 70 60 80
后序遍历: 20 40 30 60 80 70 50
成功找到节点: 60
删除节点30后【中序遍历】: 20 40 50 60 70 80
五、核心函数原理详解
1. 节点插入
递归找空位置,小的往左、大的往右,重复数据直接忽略。
2. 节点查找
利用 BST 有序性,每次减半搜索范围,效率远高于普通遍历。
3. 节点删除(重难点)
BST 删除分三种情况:
-
无孩子:直接释放当前节点
-
单个孩子:用孩子顶替当前节点
-
两个孩子 :右子树最小值替换 + 删除最小值节点(本文标准写法)
4. 三种遍历区别
-
前序:根左右(用于复制树、获取结构)
-
中序:左根右(BST 升序输出,最常用)
-
后序:左右根(用于销毁树、计算树高度)
六、知识点总结(面试/考试必备)
-
二叉搜索树的最大优势:查找、插入、删除效率高,理想时间复杂度 O(logn)
-
BST 中序遍历一定是有序数组
-
删除双孩子节点必须用后继/前驱节点替换,保证树结构不变
-
必须手动 free 节点,避免内存泄漏