基础查找算法(三)二叉树查找

一 定义

二叉排序树(Binary Sort Tree),也称为二叉搜索树(Binary Search Tree),是一种高效的数据结构,特别适合动态数据的查找、插入和删除操作

二 特性说明

特性 说明
核心性质 左子树所有节点值 < 根节点值 ≤ 右子树所有节点值
中序遍历 产生一个递增的有序序列
时间复杂度 平均 O(log n),最坏 O(n)(退化为链表时)
空间复杂度 O(n) 存储树结构,递归实现查找为 O(log n) 栈空间
主要优点 动态性、结构灵活、支持高效查找和排序
主要缺点 性能依赖树的平衡性,可能退化为链表

三 算法原理

二叉排序树是一种动态树表,其核心特性是递归的有序性

3.1 基本性质

若左子树非空,则左子树上所有节点值均小于根节点的值
若右子树非空,则右子树上所有节点值均大于根节点的值
左右子树也分别为二叉排序树

3.2 中序有序性

对二叉排序树进行中序遍历(左-根-右),可以得到一个递增的有序序列。这是二叉排序树的一个重要性质,也使其可用于排序操作。

3.3 动态操作原理

查找:从根节点开始,比较目标值与当前节点值,决定向左/右子树递归查找
插入:先查找合适位置,新节点总是作为叶子节点插入
删除:分三种情况处理(叶子节点、单子树节点、双子树节点)

四 代码实现

4.1 c 语言实现

以下是二叉排序树的完整C语言实现,包含查找、插入、删除等核心操作

4.1.1 实现

#include <stdio.h>
#include <stdlib.h>

// 二叉排序树节点结构
typedef struct BSTNode {
    int key;  // 关键字
    struct BSTNode *lchild, *rchild;  // 左右孩子指针
} BSTNode, *BSTree;

// 查找操作(递归实现)
BSTNode* SearchBST(BSTree T, int key) {
    if (T == NULL || key == T->key) {
        return T;  // 找到或树为空
    } else if (key < T->key) {
        return SearchBST(T->lchild, key);  // 在左子树中继续查找
    } else {
        return SearchBST(T->rchild, key);  // 在右子树中继续查找
    }
}

// 插入操作
int InsertBST(BSTree *T, int key) {
    if (*T == NULL) {
        // 创建新节点作为叶子节点插入
        *T = (BSTNode*)malloc(sizeof(BSTNode));
        (*T)->key = key;
        (*T)->lchild = (*T)->rchild = NULL;
        return 1;  // 插入成功
    } else if (key == (*T)->key) {
        return 0;  // 树中已存在相同关键字,插入失败
    } else if (key < (*T)->key) {
        return InsertBST(&(*T)->lchild, key);  // 插入到左子树
    } else {
        return InsertBST(&(*T)->rchild, key);  // 插入到右子树
    }
}

// 查找最小节点(用于删除操作)
BSTNode* FindMin(BSTree T) {
    while (T != NULL && T->lchild != NULL) {
        T = T->lchild;
    }
    return T;
}

// 删除操作
int DeleteBST(BSTree *T, int key) {
    if (*T == NULL) return 0;  // 空树或未找到
    
    if (key < (*T)->key) {
        return DeleteBST(&(*T)->lchild, key);  // 在左子树中删除
    } else if (key > (*T)->key) {
        return DeleteBST(&(*T)->rchild, key);  // 在右子树中删除
    } else {
        // 找到要删除的节点,分三种情况处理
        if ((*T)->lchild == NULL) {
            // 情况1:只有右子树或无子树
            BSTNode *temp = *T;
            *T = (*T)->rchild;
            free(temp);
        } else if ((*T)->rchild == NULL) {
            // 情况2:只有左子树
            BSTNode *temp = *T;
            *T = (*T)->lchild;
            free(temp);
        } else {
            // 情况3:有左右子树,用右子树的最小值替代
            BSTNode *minNode = FindMin((*T)->rchild);
            (*T)->key = minNode->key;  // 值替换
            return DeleteBST(&(*T)->rchild, minNode->key);  // 删除右子树中的最小值节点
        }
        return 1;  // 删除成功
    }
}

// 中序遍历(验证二叉排序树性质)
void InOrderTraversal(BSTree T) {
    if (T != NULL) {
        InOrderTraversal(T->lchild);
        printf("%d ", T->key);
        InOrderTraversal(T->rchild);
    }
}

// 主函数示例
int main() {
    BSTree root = NULL;
    int keys[] = {45, 24, 53, 12, 37, 93};
    int n = sizeof(keys) / sizeof(keys[0]);
    
    // 构建二叉排序树
    for (int i = 0; i < n; i++) {
        InsertBST(&root, keys[i]);
    }
    
    printf("中序遍历结果: ");
    InOrderTraversal(root);  // 输出应为有序序列
    printf("\n");
    
    // 查找示例
    int target = 37;
    BSTNode *result = SearchBST(root, target);
    if (result != NULL) {
        printf("找到关键字 %d\n", target);
    } else {
        printf("未找到关键字 %d\n", target);
    }
    
    // 删除示例
    DeleteBST(&root, 24);
    printf("删除节点24后的中序遍历: ");
    InOrderTraversal(root);
    printf("\n");
    
    return 0;
}

4.1.2 代码详解

4.1.2.1 数据结构定义:

每个节点包含关键字和左右孩子指针
使用递归定义,符合树的自然结构

4.1.2.2 查找算法:

递归基线:树为空或找到目标值时返回
递归过程:根据比较结果决定向左/右子树递归查找
时间复杂度:取决于树高,最好O(log n),最坏O(n)

4.1.2.3 插入算法:

查找位置:找到合适的插入位置(叶子节点位置)
新建节点:总是在叶子位置插入新节点
保持有序:插入后仍满足二叉排序树性质

4.1.2.4 删除算法(重点)

叶子节点:直接删除,不影响树结构
单子树节点:用其子树替换自身
双子树节点:用直接前驱或后继替换,然后删除前驱/后继节点

五 性能分析

二叉排序树的性能高度依赖于树的形态,下面通过两种极端情况对比说明:

5.1 最好情况(树平衡):

树的高度接近log₂n,形态均匀
平均查找长度ASL = O(log n),效率接近二分查找

5.2 最坏情况(树退化为链表):

插入序列有序时发生,树高为n
平均查找长度ASL = (n+1)/2,效率退化为顺序查找

5.3 空间复杂度:

存储整个树需要O(n)空间
递归实现的栈深度为O(h),h为树高

六 算法比较

算法 数据结构 平均时间复杂度 优点 缺点 适用场景
二叉排序树 二叉树 O(log n) 动态性,支持高效插入删除 可能退化为O(n) 动态数据集合,频繁插入删除
平衡二叉树(AVL) 平衡二叉树 O(log n) 严格平衡,性能稳定 插入删除需要旋转操作 查询频繁,对性能要求稳定
哈希查找 哈希表 O(1) 查找速度极快 需要处理冲突,不支持范围查询 等值查询,不涉及排序
顺序查找 数组/链表 O(n) 实现简单,无需排序 效率低下 小规模数据或无序数据
二分查找 有序数组 O(log n) 效率高 需要有序数组,插入删除困难 静态有序数据

七 总结

二叉排序树是一种兼顾查找效率与动态操作的数据结构,通过有序的二叉树结构实现高效查找。其核心价值在于:

  • 动态性能:支持高效的查找、插入和删除操作,适合动态数据集合
  • 排序特性:中序遍历自然产生有序序列,兼具排序功能
  • 结构灵活:采用链式存储,无需移动大量元素

然而,二叉排序树的性能依赖于树的平衡性,在极端情况下可能退化为链表。为此,在实际应用中常使用其平衡变种(如AVL树、红黑树)来保证性能稳定性。

适用场景:适合数据动态变化频繁、需要维护有序性的场景,如数据库索引、内存数据管理等。对于查询远多于更新的场景,可考虑更平衡的树结构;对于静态数据,二分查找可能是更好选择。

posted on 2025-11-13 09:49  weiwei2021  阅读(6)  评论(0)    收藏  举报