【附C源码】二叉搜索树的C语言实现

【附C源码】二叉搜索树的C语言实现

前言

二叉搜索树(Binary Search Tree,BST)作为一种基础且重要的数据结构,在计算机科学领域有着广泛的应用。本文将介绍一种基于C语言的二叉搜索树实现方案,涵盖其核心原理、代码实现细节以及使用方式。

核心原理

二叉搜索树的核心性质在于:对于树中的任意节点,其左子树中所有节点的值均小于该节点的值,右子树中所有节点的值均大于该节点的值。这一性质保证了中序遍历二叉搜索树时,输出结果必然是有序的。

基于这一性质,二叉搜索树在平均情况下能够以 O(log n) 的时间复杂度完成插入、删除和查找操作。当然,在最坏情况下(如树退化为链表),时间复杂度会退化为 O(n),这也是后续需要引入平衡机制的原因。

数据结构定义

首先定义树节点和树结构体:

c 复制代码
typedef int Data;

typedef struct TreeNode {
    Data data;
    struct TreeNode* left;
    struct TreeNode* right;
} TreeNode;

typedef struct {
    TreeNode* root;
    int size;
} Tree;

此处采用 typedef int Data 的方式对数据类型进行抽象,便于后续扩展为其他类型。树结构体中维护 size 字段,使得获取节点数量的操作能够在 O(1) 时间内完成。

关键操作实现

节点插入

插入操作的核心逻辑是从根节点出发,根据待插入值与当前节点值的大小关系,决定向左子树或右子树递归查找,直至找到合适的空位置:

c 复制代码
bool treeInsert(Tree* t, Data val) {
    TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));
    newNode->data = val;
    newNode->left = NULL;
    newNode->right = NULL;
    
    if (!t->root) {
        t->root = newNode;
        t->size++;
        return true;
    }
    
    TreeNode* current = t->root;
    TreeNode* parent = NULL;
    
    while (current) {
        parent = current;
        if (val < current->data) {
            current = current->left;
        } else if (val > current->data) {
            current = current->right;
        } else {
            free(newNode);  // 重复值不插入
            return false;
        }
    }
    
    if (val < parent->data) {
        parent->left = newNode;
    } else {
        parent->right = newNode;
    }
    t->size++;
    return true;
}

该实现采用迭代方式而非递归,避免了函数调用栈的开销。同时,代码中明确处理了重复值的情况,保证树中不存在重复节点。

节点删除

删除操作是二叉搜索树中最复杂的操作,需要根据待删除节点的子节点数量分三种情况处理:

  1. 叶子节点:直接删除,无需额外操作
  2. 单子节点:用子节点替代被删除节点
  3. 双子节点:用右子树的最小值(或左子树的最大值)替代被删除节点,然后递归删除该最小值节点
c 复制代码
TreeNode* treeRemoveNode(TreeNode* node, Data val) {
    if (!node) return NULL;
    
    if (val < node->data) {
        node->left = treeRemoveNode(node->left, val);
    } else if (val > node->data) {
        node->right = treeRemoveNode(node->right, val);
    } else {
        if (!node->left) {
            TreeNode* temp = node->right;
            free(node);
            return temp;
        } else if (!node->right) {
            TreeNode* temp = node->left;
            free(node);
            return temp;
        }
        
        TreeNode* temp = treeFindMin(node->right);
        node->data = temp->data;
        node->right = treeRemoveNode(node->right, temp->data);
    }
    return node;
}

此处选择右子树的最小值作为替代节点,是因为该值必然大于左子树所有节点且小于右子树其余节点,满足二叉搜索树的性质。

树的遍历

三种基本遍历方式的递归实现:

c 复制代码
void treeInOrderNode(TreeNode* node) {
    if (!node) return;
    treeInOrderNode(node->left);
    printf("%d ", node->data);
    treeInOrderNode(node->right);
}

中序遍历的输出结果即为升序序列,这一特性在实际应用中经常被利用。前序遍历和后序遍历的实现结构类似,仅调整访问顺序即可。

可视化输出

为了便于调试和验证,实现了一个简单的树形打印函数:

c 复制代码
void treePrintNode(TreeNode* node, int depth) {
    if (!node) return;
    
    treePrintNode(node->right, depth + 1);
    
    for (int i = 0; i < depth; i++) {
        printf("    ");
    }
    printf("%d\n", node->data);
    
    treePrintNode(node->left, depth + 1);
}

该函数采用右-根-左的遍历顺序,配合缩进输出,使得树的结构能够直观地呈现在终端上。

内存管理

C语言不像高级语言具备自动垃圾回收机制,因此内存管理需要格外谨慎。本实现中,销毁树的操作采用后序遍历的顺序递归释放节点:

c 复制代码
void treeNodeDestroy(TreeNode* node) {
    if (!node) return;
    treeNodeDestroy(node->left);
    treeNodeDestroy(node->right);
    free(node);
}

必须确保子节点先于父节点释放,否则会导致内存泄漏或访问非法内存。

使用示例

以下是一个完整的使用示例:

c 复制代码
int main() {
    Tree* t = treeCreate();
    
    treeInsert(t, 50);
    treeInsert(t, 30);
    treeInsert(t, 70);
    treeInsert(t, 20);
    treeInsert(t, 40);
    
    treePrint(t);
    treeInOrder(t);
    
    printf("树高度: %d\n", treeHeight(t));
    printf("叶子节点数: %d\n", treeCountLeaves(t));
    
    treeRemove(t, 30);
    treePrint(t);
    
    treeDestroy(t);
    return 0;
}

性能分析

操作 平均时间复杂度 最坏时间复杂度
插入 O(log n) O(n)
删除 O(log n) O(n)
查找 O(log n) O(n)
遍历 O(n) O(n)

当数据以随机顺序插入时,树的高度接近 log n,各项操作效率较高。但如果数据已排序,树将退化为链表,此时需要考虑引入AVL树或红黑树等自平衡机制。

总结

本文介绍了一种完整的二叉搜索树C语言实现方案。该实现涵盖了树的基本操作,代码结构清晰,注释完整,适合作为数据结构学习的参考材料。对于生产环境的使用,建议在此基础上增加错误处理机制,并根据实际场景考虑是否需要引入平衡策略。

完整的代码实现可在文末获取,如有问题或建议,欢迎交流讨论。


⚠️源码地址:https://github.com/anjuxi/C-binary_search_-tree/tree/main

相关推荐
C+++Python1 小时前
C++ 泛型编程 极简示例代码
开发语言·c++
Rust研习社1 小时前
Ubuntu 全面拥抱 Rust 后,我意识到 Rust 社区要变了
linux·服务器·开发语言·后端·ubuntu·rust
宵时待雨1 小时前
回溯算法专题2:二叉树中的深搜
开发语言·数据结构·c++·笔记·算法·深度优先
jiayong231 小时前
第 43 课:任务详情抽屉里的批量处理闭环与删除联动
java·开发语言·前端
likerhood1 小时前
Java 访问修饰符:public、protected、private讲解
java·开发语言·javascript
刀法如飞2 小时前
JavaScript 数组去重的 20 种实现方式,学会用不同思路解决问题
前端·javascript·算法
洛水水2 小时前
【力扣100题】46.单词拆分
算法·leetcode·职场和发展
学不思则罔2 小时前
ParallelStream并发陷阱解析
java·开发语言·windows
认真的小羽❅2 小时前
【Java并发编程】volatile关键字深度解析:从内存语义到实际应用
java·开发语言