基础查找算法(三)二叉树查找
一 定义
二叉排序树(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) 收藏 举报
浙公网安备 33010602011771号