欢迎关注我的公众号是【CodeAllen】,关注回复【1024】获取精品学习资源
程序员技术交流①群:736386324 ,程序员技术交流②群:371394777

目录

二叉排序树查找关键字

二叉排序树中插入关键字

二叉排序树中删除关键字

总结


二叉排序树查找关键字

二叉排序树中查找某关键字时,查找过程类似于次优二叉树,在二叉排序树不为空树的前提下,首先将被查找值同树的根结点进行比较,会有 3 种不同的结果:
  • 如果相等,查找成功;
  • 如果比较结果为根结点的关键字值较大,则说明该关键字可能存在其左子树中;
  • 如果比较结果为根结点的关键字值较小,则说明该关键字可能存在其右子树中;
实现函数为:(运用递归的方法)
BiTree SearchBST(BiTree T,KeyType key){//如果递归过程中 T 为空,则查找结果,返回NULL;或者查找成功,返回指向该关键字的指针if (!T || key==T->data) {return T;}else if(key<T->data){//递归遍历其左孩子return SearchBST(T->lchild, key);}else{//递归遍历其右孩子return SearchBST(T->rchild, key);}
}

二叉排序树中插入关键字

二叉排序树本身是动态查找表的一种表示形式,有时会在查找过程中插入或者删除表中元素,当因为查找失败而需要插入数据元素时,该数据元素的插入位置一定位于二叉排序树的叶子结点,并且一定是查找失败时访问的最后一个结点的左孩子或者右孩子
例如,在下图 的二叉排序树中做查找关键字 1 的操作,当查找到关键字 3 所在的叶子结点时,判断出表中没有该关键字,此时关键字 1 的插入位置为关键字 3 的左孩子。
所以,二叉排序树表示动态查找表做插入操作,只需要稍微更改一下上面的代码就可以实现,具体实现代码为:
BOOL SearchBST(BiTree T,KeyType key,BiTree f,BiTree *p){//如果 T 指针为空,说明查找失败,令 p 指针指向查找过程中最后一个叶子结点,并返回查找失败的信息if (!T){*p=f;return false;}//如果相等,令 p 指针指向该关键字,并返回查找成功信息else if(key==T->data){*p=T;return true;}//如果 key 值比 T 根结点的值小,则查找其左子树;反之,查找其右子树else if(key<T->data){return SearchBST(T->lchild,key,T,p);}else{return SearchBST(T->rchild,key,T,p);}
}
//插入函数
BOOL InsertBST(BiTree T,ElemType e){BiTree p=NULL;//如果查找不成功,需做插入操作if (!SearchBST(T, e,NULL,&p)) {//初始化插入结点BiTree s=(BiTree)malloc(sizeof(BiTree));s->data=e;s->lchild=s->rchild=NULL;//如果 p 为NULL,说明该二叉排序树为空树,此时插入的结点为整棵树的根结点if (!p) {T=s;}//如果 p 不为 NULL,则 p 指向的为查找失败的最后一个叶子结点,只需要通过比较 p 和 e 的值确定 s 到底是 p 的左孩子还是右孩子else if(e<p->data){p->lchild=s;}else{p->rchild=s;}return true;}//如果查找成功,不需要做插入操作,插入失败return false;
}
通过使用二叉排序树对动态查找表做查找和插入的操作,同时在中序遍历二叉排序树时,可以得到有关所有关键字的一个有序的序列。
例如,假设原二叉排序树为空树,在对动态查找表  {3,5,7,2,1}  做查找以及插入操作时,可以构建出一个含有表中所有关键字的二叉排序树,过程如下图所示:
通过不断的查找和插入操作,最终构建的二叉排序树如图 2(5) 所示。当使用中序遍历算法遍历二叉排序树时,得到的序列为: 1 2 3 5 7  ,为有序序列。
一个无序序列可以通过构建一棵二叉排序树,从而变成一个有序序列。

二叉排序树中删除关键字

在查找过程中,如果在使用二叉排序树表示的动态查找表中删除某个数据元素时,需要在成功删除该结点的同时,依旧使这棵树为二叉排序树。
假设要删除的为结点 p,则对于二叉排序树来说,需要根据结点 p 所在不同的位置作不同的操作,有以下 3 种可能:
1、结点 p 为叶子结点,此时只需要删除该结点,并修改其双亲结点的指针即可;
2、结点 p 只有左子树或者只有右子树,如果 p 是其双亲节点的左孩子,则直接将 p 节点的左子树或右子树作为其双亲节点的左子树;反之也是如此,如果 p 是其双亲节点的右孩子,则直接将 p 节点的左子树或右子树作为其双亲节点的右子树;
3、结点 p 左右子树都有,此时有两种处理方式:
1)令结点 p 的左子树为其双亲结点的左子树;结点 p 的右子树为其自身直接前驱结点的右子树,如下图所示;
2)用结点 p 的直接前驱(或直接后继)来代替结点 p,同时在二叉排序树中对其直接前驱(或直接后继)做删除操作。如下图为使用直接前驱代替结点 p:
上图中,在对左图进行中序遍历时,得到的结点 p 的直接前驱结点为结点 s,所以直接用结点 s 覆盖结点 p,由于结点 s 还有左孩子,根据第 2 条规则,直接将其变为双亲结点的右孩子。
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define ElemType int
#define  KeyType int
/* 二叉排序树的节点结构定义 */
typedef struct BiTNode
{int data;struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;//二叉排序树查找算法
int SearchBST(BiTree T, KeyType key, BiTree f, BiTree *p) {//如果 T 指针为空,说明查找失败,令 p 指针指向查找过程中最后一个叶子结点,并返回查找失败的信息if (!T) {*p = f;return FALSE;}//如果相等,令 p 指针指向该关键字,并返回查找成功信息else if (key == T->data) {*p = T;return TRUE;}//如果 key 值比 T 根结点的值小,则查找其左子树;反之,查找其右子树else if (key < T->data) {return SearchBST(T->lchild, key, T, p);}else {return SearchBST(T->rchild, key, T, p);}
}
int InsertBST(BiTree *T, ElemType e) {BiTree p = NULL;//如果查找不成功,需做插入操作if (!SearchBST((*T), e, NULL, &p)) {//初始化插入结点BiTree s = (BiTree)malloc(sizeof(BiTNode));s->data = e;s->lchild = s->rchild = NULL;//如果 p 为NULL,说明该二叉排序树为空树,此时插入的结点为整棵树的根结点if (!p) {*T = s;}//如果 p 不为 NULL,则 p 指向的为查找失败的最后一个叶子结点,只需要通过比较 p 和 e 的值确定 s 到底是 p 的左孩子还是右孩子else if (e < p->data) {p->lchild = s;}else {p->rchild = s;}return TRUE;}//如果查找成功,不需要做插入操作,插入失败return FALSE;
}
//删除函数
int Delete(BiTree *p)
{BiTree q, s;//情况 1,结点 p 本身为叶子结点,直接删除即可if (!(*p)->lchild && !(*p)->rchild) {*p = NULL;}else if (!(*p)->lchild) { //左子树为空,只需用结点 p 的右子树根结点代替结点 p 即可;q = *p;*p = (*p)->rchild;free(q);}else if (!(*p)->rchild) {//右子树为空,只需用结点 p 的左子树根结点代替结点 p 即可;q = *p;*p = (*p)->lchild;//这里不是指针 *p 指向左子树,而是将左子树存储的结点的地址赋值给指针变量 pfree(q);}else {//左右子树均不为空,采用第 2 种方式q = *p;s = (*p)->lchild;//遍历,找到结点 p 的直接前驱while (s->rchild){q = s;s = s->rchild;}//直接改变结点 p 的值(*p)->data = s->data;//判断结点 p 的左子树 s 是否有右子树,分为两种情况讨论if (q != *p) {q->rchild = s->lchild;//若有,则在删除直接前驱结点的同时,令前驱的左孩子结点改为 q 指向结点的孩子结点}else {q->lchild = s->lchild;//否则,直接将左子树上移即可}free(s);}return TRUE;
}
int DeleteBST(BiTree *T, int key)
{if (!(*T)) {//不存在关键字等于key的数据元素return FALSE;}else{if (key == (*T)->data) {Delete(T);return TRUE;}else if (key < (*T)->data) {//使用递归的方式return DeleteBST(&(*T)->lchild, key);}else {return DeleteBST(&(*T)->rchild, key);}}
}
void order(BiTree t)//中序输出
{if (t == NULL) {return;}order(t->lchild);printf("%d ", t->data);order(t->rchild);
}
int main()
{int i;int a[5] = { 3,4,2,5,9 };BiTree T = NULL;for (i = 0; i < 5; i++) {InsertBST(&T, a[i]);}printf("中序遍历二叉排序树:\n");order(T);printf("\n");printf("删除3后,中序遍历二叉排序树:\n");DeleteBST(&T, 3);order(T);
}
运行结果:
中序遍历二叉排序树:
2 3 4 5 9
删除3后,中序遍历二叉排序树:
2 4 5 9

总结

使用二叉排序树在查找表中做查找操作的时间复杂度 同建立的二叉树本身的结构有关。即使查找表中各数据元素完全相同,但是不同的排列顺序,构建出的二叉排序树大不相同。
例如:查找表  {45,24,53,12,37,93}  和表  {12,24,37,45,53,93}  各自构建的二叉排序树图下图所示:
使用二叉排序树实现动态查找操作的过程,实际上就是从二叉排序树的根结点到查找元素结点的过程,所以时间复杂度同被查找元素所在的树的深度(层次数)有关。
为了弥补二叉排序树构造时产生如图 5 右侧所示的影响算法效率的因素,需要对二叉排序树做“平衡化”处理,使其成为一棵平衡二叉树。

【大话数据结构C语言】56 二叉排序树的查找、插入和删除相关推荐

  1. c语言折半查找输出坐标,数据结构(C语言版)——有序表查找(折半查找)(代码版)...

    数据结构(C语言版)--有序表查找(折半查找)(代码版) 数据结构(C语言版)--有序表查找(折半查找)(代码版) #include #include #define ERROR 0 #define ...

  2. 《大话数据结构》笔记——第8章 查找(二)

    文章目录 8.6 二叉排序树 8.6.1 二叉排序树查找操作 8.6.2 二叉排序树插入操作 8.6.3 二叉排序树删除操作 8.6.4 二叉排序树总结 8.7 平衡二叉树( AVL树 ) 8.7.1 ...

  3. 《大话数据结构》笔记——第8章 查找(一)

    文章目录 8.1 开场白 8.2 查找概述 8.3 顺序查找 8.3.1 顺序表查找算法 8.3.2 顺序表查找优化 8.4 有序表查找 8.4.1 折半查找 8.4.2 插值查找 8.4.3 斐波那 ...

  4. 数据结构(8-3)二叉排序树(查找、插入删除)

    目录 一.基础理论 1.特点: 2.结构: 二.查找 三.插入 四.删除 1.被删除的结点D是叶子结点 2.被删除的结点D仅有一个孩子 2-1.删除结点14(有左无右) 2-2.删除结点 10 (有右 ...

  5. 数据结构之算法(二叉排序树的查找分析)

    在二叉排序树上查找其关键字等于给定值的结点的过程,恰是走了一条从根结点到该结点的路径的过程,和给定值比较的关键字个数等于路径长度加1(或结点所在层次数),因此,和折半查找类似,与给定值比较的关键字个数 ...

  6. 数据结构Java实现03----单向链表的插入和删除b

    文本主要内容: 链表结构 单链表代码实现 单链表的效率分析 一.链表结构: (物理存储结构上不连续,逻辑上连续:大小不固定)            概念: 链式存储结构是基于指针实现的.我们把一个数据 ...

  7. 【大话数据结构C语言】62 散列表(哈希表)查找

    欢迎关注我的公众号是[CodeAllen],关注回复[1024]获取精品学习资源 程序员技术交流①群:736386324  程序员技术交流②群:371394777 什么是散列表? 在初中的数学课本中学 ...

  8. 【大话数据结构C语言】57 平衡二叉树(AVL树)

    欢迎关注我的公众号是[CodeAllen],关注回复[1024]获取精品学习资源 程序员技术交流①群:736386324 ,程序员技术交流②群:371394777 平衡二叉排序树 平衡二叉树是一种二叉 ...

  9. 《大话数据结构》笔记——第8章 查找(四)

    文章目录 8.9 散列表查找( 哈希表 )概述 8.9.1 散列表查找定义 8.9.2 散列表查找步骤 8.10 散列函数的构造方法 8.10.1 直接定制法 8.10.2 数字分析法 8.10.3 ...

最新文章

  1. 判定是否互为字符重排
  2. JS基础篇之作用域、执行上下文、this、闭包
  3. pandas中的括号索引
  4. [Codeforces700E Cool Slogans]
  5. C++11 并发指南四(future 详解三 std::future std::shared_future)
  6. 聚簇索引和非聚簇索引的区别_学习索引的一些总结
  7. linux下jtag命令,[转载]LINUX内核调试过程(使用OpenJtag + OpenOCD)
  8. HeadFirst设计模式笔记——命令模式
  9. python-docx读取word段落的样式字体
  10. 小新air14学计算机,小新Air14对比小新Pro13哪个更香,盘点办公学习的
  11. linux下增加宋体 仿宋 字体
  12. arcgis导出的图片无效_img影像在arcgis中生成JPG图片空白求解
  13. python中pip安装报错的一些总结
  14. 数据库系统原理与应用教程(041)—— MySQL 查询(三):设置查询条件
  15. 键盘的某些键坏了咋办(如delete键等)
  16. 陀螺仪随机误差的Allan方差分析
  17. 终于等到了!十位Java架构师整理的“阿里P7”养成计划
  18. 杜兰特全部比赛录像合集【百度网盘高清分享】
  19. linux中修改某行某列字符串,Linux替换指定列的字符串(awk 命令)
  20. 书柜例子解释整理表空间碎片

热门文章

  1. 计算机网络-第1章 计算机网络和因特网-同步电大进度
  2. 拼多多搜索词统计 API接口操作展示说明
  3. 网吧遭雷击“瘫痪” 专家:别忘加保护装置(转)
  4. SLAM中多目三角化
  5. 最好的生活方式:存钱,运动,读书,早起
  6. python绘制8×8棋盘_python图形工具turtle绘制国际象棋棋盘
  7. [RK3399][Android7.1] Audio中的Ducking模式
  8. 利用python爬取贝壳网租房信息
  9. 「数据架构」介绍下一代主数据管理(MDM)
  10. DP分类题目 转载 《志当存高远》大神的 没有冒犯的意思 只是拿过来学习的