【数据结构】二叉排序树(查找+插入+删除+效率分析)完整代码+解析
创作时间:
作者:
@小白创作中心
【数据结构】二叉排序树(查找+插入+删除+效率分析)完整代码+解析
引用
CSDN
1.
https://blog.csdn.net/m0_61628700/article/details/138794131
二叉排序树(Binary Search Tree,BST)是一种重要的数据结构,它能够高效地支持查找、插入和删除操作。本文将详细介绍二叉排序树的基本概念、操作方法及其效率分析,并提供完整的代码实现。
3.1 二叉排序树
3.1.1 定义
二叉排序树又称二叉查找树(BST,Binary Search Tree),是一种具有以下性质的二叉树:
- 左子树结点值 < 根结点值 < 右子树结点值
进行中序遍历,可以得到一个递增的有序序列。
3.1.2 查找操作
步骤:
- 若树非空,目标值与根结点的值比较;
- 若相等,则查找成功;
- 若小于根结点,则在左子树上查找;
- 否则在右子树上查找;
- 查找成功返回结点指针;查找失败返回NULL。
代码实现:
//二叉排序树结点
typedef struct BSTree{
int key;
struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
//在二叉排序树中查找值为key的结点
BSTNode *BST_search(BSTree T,int key){
//若树为空或等于根结点值,则结束循环
while(T!=NULL&&key!=T->key){
if(key<T->key)
T=T->lchild; //key小,则在左子树上找
else
T=T->rchild; //key大,则在右子树上找
}
return T;
}
递归实现:
BSTNode *BSTSearch(BSTree T,int key){
if(T==NULL)
return NULL;
if(key==T->key)
return T;
else if(key<T->key)
return BSTSearch(T->lchild,key); //递归在左树中找
else
return BSTSearch(T->rchild,key); //递归在右子树中找
}
递归的最坏空间复杂度是O(h),非递归是O(1),所以非递归效率更加好。
3.1.3 插入操作
思路:
- 若原二叉树为空,则直接插入结点;
- 否则,若关键字k小于根结点值,则插入到左子树;
- 若关键字k大于根结点值,则插入到右子树。
代码实现:
//在二叉排序树插入关键字为k的新结点(递归实现)
int BST_Insert(BSTree &T,int k){
//原树为空,新插入的结点为根结点
if(T==NULL){
T=(BSTree)malloc(sizeof(BSTNode));
T->key=k;
T->lchild=T->rchild=NULL;
return 1;
}
else if(k==T->key) //树中存在相同关键字的结点,插入失败
return 0;
else if(k<T->key) //插入到T的左子树
return BST_Insert(T->lchild,k);
else //插入到T的右子树
return BST_Insert(T->rchild,k);
}
最坏空间复杂度:O(h)
二叉排序树的构造:
//按str[]中的关键字序列建立二叉树
void Creat_BST(BSTree &T,int str[],int n){
T=NULL;
int i=0;
//依次将每个关键字插入到二叉排序树中
while(i<n){
BST_Insert(T,str[i]);
i++;
}
}
注:不同的关键字序列可能得到同款二叉排序树,也可能不同。
3.1.4 删除操作
步骤:
- 先搜索找到目标结点:
- 若被删结点z是叶子结点,则直接删除,不会破坏二叉排序树的性质。
- 若结点z只有一棵左子树或右子树,则让z的子树成为z的子树成为z父节点的子树,代替z的位置。
- 若z既有左子树又有右子树:
- 方法一:则令z的直接后继(中序遍历z子树后的第一个结点)代替z,然后从二叉排序树中删去这个直接后继。
- z的后继:z的右子树中最左下结点(该结点一定没有左子树)。
- 方法二:用直接前驱替换直接后继,其他方法不变。
- z的前驱:z的左子树中最右下结点(该结点一定没有右子树)。
3.1.5 效率分析
查找长度:
在查找运算中,需要对比关键字的次数称为查找长度,反映了查找操作时间复杂度。
时间复杂度:
最差情况下O(h),即为树高
完整代码实现
#include <iostream>
using namespace std;
//二叉排序树结点
typedef struct BSTNode{
int key;
struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
// 在二叉排序树中搜索关键字为key的结点
BSTNode* BSTSearch(BSTree T, int key) {
if (T == NULL || T->key == key)
return T;
if (key < T->key)
return BSTSearch(T->lchild, key);
else
return BSTSearch(T->rchild, key);
}
// 在二叉排序树中查找最小值结点
BSTNode* findMin(BSTree T) {
if (T == NULL)
return NULL;
else if (T->lchild == NULL)
return T;
else
return findMin(T->lchild);
}
// 删除结点z
void BST_Delete(BSTree &T, int key) {
if (T == NULL)
return;
else if (key < T->key)
BST_Delete(T->lchild, key);
else if (key > T->key)
BST_Delete(T->rchild, key);
else {
// 找到了要删除的结点
if (T->lchild && T->rchild) {
// 如果有两个子节点
BSTNode* minRight = findMin(T->rchild); // 找到右子树的最小值结点
T->key = minRight->key; // 用右子树的最小值替换当前结点
BST_Delete(T->rchild, minRight->key); // 删除右子树的最小值结点
} else {
// 如果只有一个子节点或者是叶子结点
BSTNode* temp = T;
if (T->lchild == NULL) // 如果只有右子树或者是叶子结点
T = T->rchild;
else if (T->rchild == NULL) // 如果只有左子树
T = T->lchild;
free(temp); // 释放删除结点的内存
}
}
}
//在二叉排序树插入关键字为k的新结点(递归实现)
int BST_Insert(BSTree &T,int k){
//原树为空,新插入的结点为根结点
if(T==NULL){
T=(BSTree)malloc(sizeof(BSTNode));
T->key=k;
T->lchild=T->rchild=NULL;
return 1;
}
else if(k==T->key) //树中存在相同关键字的结点,插入失败
return 0;
else if(k<T->key) //插入到T的左子树
return BST_Insert(T->lchild,k);
else //插入到T的右子树
return BST_Insert(T->rchild,k);
}
//按str[]中的关键字序列建立二叉树
void Creat_BST(BSTree &T,int str[],int n){
T=NULL;
int i=0;
//依次将每个关键字插入到二叉排序树中
while(i<n){
BST_Insert(T,str[i]);
i++;
}
}
// 中序遍历打印二叉排序树
void InOrder(BSTree T) {
if (T != NULL) {
InOrder(T->lchild);
cout << T->key << " ";
InOrder(T->rchild);
}
}
int main() {
BSTree T = NULL;
// 插入操作测试
int arr[] = {50, 30, 70, 20, 40, 60, 80};
int n = sizeof(arr) / sizeof(arr[0]);
Creat_BST(T, arr, n);
cout << "Binary Search Tree (Inorder): ";
InOrder(T);
cout << endl;
// 搜索操作测试
int searchKey = 40;
BSTNode* searchResult = BSTSearch(T, searchKey);
if (searchResult != NULL)
cout << "Key " << searchKey << " found in the tree." << endl;
else
cout << "Key " << searchKey << " not found in the tree." << endl;
// 删除操作测试
int deleteKey = 30;
cout << "Deleting key " << deleteKey << endl;
BST_Delete(T, deleteKey);
cout << "Binary Search Tree after deletion: ";
InOrder(T);
cout << endl;
return 0;
}
热门推荐
用手机Miracast无线投屏前须知的7个关键事实
Miracast投屏-Miracast投屏的使用条件、方法步骤
车厘子:降脂助眠的营养水果,高钾人群需谨慎
车厘子吃多了会中毒?医生:这些说法都是谣言
车厘子:夏冬两季尝鲜,抗氧化助眠的营养水果
车厘子价格腰斩却暗藏玄机,专家解析选购要点
乌岽单丛:凤凰单丛茶中的贵族
冬日里的温暖之选:凤凰单丛茶的养生之道
凤凰单丛茶:九百年茶香传奇的传承与创新
刮舌苔有讲究:每天一次为宜,4类人需谨慎
小米手机全面检测指南:从基础到性能深度解析
【以案释法】没有固定工作可以不支付抚养费吗?
以案释法:成年子女能否主张18周岁前应得的抚养费?
离婚后子女抚养问题全解析:抚养费、抚养权与支付标准
营养均衡,远离脑供血不足
纽约“鬼船”传说背后的文化密码
机动车撞电线酿大祸,四方面措施可有效预防
从电线到网络线:家庭走线安全指南
从家用到工程:电线电缆与断路器选型配合指南
电击伤害关键在电流,电压高低只是参考
新房布线指南:强弱电安装标准及安全要点
东山四景:太湖畔的园林、大桥、古村打卡攻略
经济学专业就业方向有哪些?9个高薪方向
五步做出餐厅级腐乳五花肉,附详细配料表
腐乳不仅不会致癌,还能降压降脂防贫血
东山岛深度游:从千年古刹到太湖大桥,两日玩转太湖明珠
苏州东山:350年古园依绿重现,成文旅融合新地标
从<道德经>看古代得道高人:谨慎、纯朴才是真智慧
《道德经》第15章:得道者九种特质的现代启示
从“冬涉川”到“若浊”:老子笔下悟道者的独特形象