查找——二叉排序树(C语言实现)

2023-10-29

二叉排序树(二叉查找树)

  1. 树表的提出:
    1)如何在一个大型的数据集合上进行动态查找?
    (1)顺序查找:不要求元素的有序性,插入、删除的性能是O(1)查找性能是O(n)<需要一个个比较>
    (2)折半查找:查找性能是O(log2n)为保证元素的有序性,插入、删除要移动元素,性能是O(n)
    2)树表(树表:将查找集合组织成树的结构–>二叉排序树)这种查找结构使得插入、删除、查找均具有较好效率。
  2. 基本概念:
    1)二叉排序树(二叉查找树):
    是一棵空的二叉树
    是具有下列性质的二叉树:
    (1)若它的左子树不空,则左子树上所有结点的值均小于根结点的值
    (2)若它的右子树不空,则右子树上所有结点的值均大于根结点的值
    (3)它的左右子树也都是二叉排序树

    2)二叉排序树是记录之间满足某种大小关系的二叉树。
  3. 二叉排序树的中序遍历结果——升序序列
    在这里插入图片描述
  4. 如何存储二叉排序树?——二叉链表(参考二叉树相关知识)

二叉树排序树的操作

  1. 插入一个元素
    1)若二叉排序树为空树,则新插入的结点为新的根结点;
    2)否则,新插入的结点必为一个新的叶子结点,其插入位置由查找过程得到。
void InsertBST(BiNode *root, int x)
{
    if (root == NULL) 
    { 
        BiNode *s = (BiNode *)malloc(sizeof(BiNode)); 
        s->data = x;
        s->lchild = s->rchild = NULL;
        root = s;
    }
    else if (root->data > x) InsertBST(root->lchild, x);//比根节点小去左子树
    else InsertBST(root->rchild, x);//比根节点大去右子树
}

  1. 二叉排序树的构造
    1)思路:<按照所给的集合的顺序,不断调用上面的插入代码>
    (1)每次插入的新结点都是二叉排序树上新的叶子结点;
    (2)找到插入位置后,不必移动其它结点,仅需修改某个结点的指针
    (3)在左子树/右子树的查找过程与在整棵树上查找过程相同;
    (4)新插入的结点没有破坏原有结点之间的关系。
    2)
void CreatBST(BiNode *root, int r[ ], int n)
{
    for (int i = 0; i < n; i++)
    {
        InsertBST(root, r[i]);
    }
}
  1. 二叉排序树的删除(设待删除结点为p,其双亲结点为f)
    1)规则:
    (1)从二叉排序树中删除一个结点之后,要仍然保持二叉排序树的特性;
    (2)当删除分支结点时破坏了二叉排序树中原有结点之间的链接关系,需要重新修改指针,使得删除结点后仍为一棵二叉排序树。
    2)
    在这里插入图片描述
    情况3:被删除的结点既有左子树也有右子树
    操作:以其左子树中的最大值结点替换之,然后再删除该结点
    在这里插入图片描述

复制删除法
如果结点有两个孩子,可以用结点的直接前驱结点代替该结点,然后再删除这个前驱结点,而前驱结点只能是下面两种情况之一:如果前驱结点是叶结点,应用第一种情况;如果它有一个孩子,应用第二种情况
在这里插入图片描述

void deleteByCopying(BiTree &T, KeyType k) 
{
  if (T==NULL) return;
  else 
  {
    if (T->data==k) delete(T);
    else if (k<T->data) deleteByCopying(T->lchild, k);
    else deleteByCopying(T->rchild, k);
  }
}
void delete(BiTree &p) 
{
  if (p->rchild==NULL) 
  {
  	q=p; 
  	p=p->lchild; 
  	free(q);
  } //只有左子树                                              
  else 
  {
  	if (p->lchild==NULL) 
  	{
  		q=p; 
  		p=p->rchild; 
  		free(q);
  	}  //只有右子树                                
 	else//p既有左子树,又有右子
 	{      
 		q=p;
    	s=p->lchild;
   		while (s->rchild)//右子树不为空继续循环
   		{
   			q=s; 
   			s=s->rchild;
   		}  //s为p的左子树的最右结点,即直接前驱,q为s的父结点
    	p->data=s->data; //用s替换p的关键字      
	    if (q!=p) 
	    {
	    	q->rchild=s->lchild;
	    }
	    else
	    {
	    	q->lchild=s->lchild;
	    }
    	free(s);
    }
}

这个算法是不对称的:它总是删除直接前驱结点,如果进行多次删除,就会减少左子树的高度而不影响右子树。进行多次删除后,整个树变得向右侧偏,右子树比左子树大得多

为了解决这个问题,可以对算法的对称性作一个简单改进:交替地从左子树删除前驱、从右子树删除后继,这叫做“对称删除法

对称删除法
1)在二叉排序树中查找给定值 k 的过程是
(1)若root是空树,则查找失败;
(2)若k=root->data,则查找成功;
(3)若k<root->data,则在root的左子树上查找;
(4)若k > root->data,在root的右子树上查找。

二叉排序树的查找效率在于只需查找二个子树之一

BiNode *SearchBST(BiNode *root, int k)
{
    if (root == NULL) return NULL;
    if (root->data == k) return root;
    else if (root->data > k)  return SearchBST(root->lchild, k);
    else  return SearchBST(root->rchild, k);
}

2)二叉排序树的查找性能取决于什么?
(1)查找的比较次数不超过树的深度
(2)插入,删除,查找的时间复杂度相同。
3)二叉排序树的深度是多少?取决于什么?——查找集合的初始排列在这里插入图片描述

实验

【问题描述】
从键盘读入<一串整数>构造一棵二叉排序树,并对得到的二叉排序树进行前序遍历。
实验要求:该二叉排序树以二叉链表存储
【输入形式】
输入一串整数(以空格分开),以-1作为结束标志,且-1不作为数据输入。
【输出形式】
<前序遍历>二叉排序树的结果
【样例输入】
23 22 11 32 21
【样例输出】
23 22 11 2 32
#include<stdio.h>
#include<stdlib.h>

typedef struct BNode
{
	int data;
	struct BNode *lchild,*rchild;
}BNode,*BiTree;

//搜索 
int Search(BiTree T,int t,BiTree T1,BiTree *p)
//从头到尾搜索,找到一个为空的,且数值合适的位置插入 
{
	if(!T)//当T为空时 
	{
		*p = T1;
		return 0;
	}
	else//当T不为空时 
	{
		if(t==T->data)//当e==T->data 
		{
			*p = T;
			return 1;
		}
		else
		{
			if(t<T->data)
				return Search(T->lchild,t,T,p);
			else
				return Search(T->rchild,t,T,p);
		}	
	}
}
int Insert(BiTree *T,int t)
{
	BiTree s,p;
	if(!Search(*T,t,NULL,&p))//SearchBST(*T,e,NULL,&p)==0
	{
		s = (BiTree)malloc(sizeof(BNode));
		s->data = t;
		s->lchild = s->rchild = NULL;
		if(!p)//p为空 
		{
			*T = s;
		}
		else
		{
			if(t<p->data)
				p->lchild = s;
			else
				p->rchild = s;
		}
		return 1;
	}
	else
		return 0;
}
int Visit(int t)
{
	printf("%d ",t);
	return 1;
}
int PreOrderTree(BiTree T,int (* Visit)(int t)) //递归前序遍历二叉树
{
	if(T)
	{
		if(Visit(T->data))
		if(PreOrderTree(T->lchild,Visit))
		if(PreOrderTree(T->rchild,Visit))
		return 1;
		return 0;
	}
	else
	return 1;
}
int Create(BiTree *T)
{
	int t;
	scanf("%d",&t);
	while(t!=-1)
	{
		Insert(T,t);
		scanf("%d",&t);
	}
	return 1;
}
int main()
{
	BiTree T=NULL;
	Create(&T);
	PreOrderTree(T,Visit);
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

查找——二叉排序树(C语言实现) 的相关文章

  • Linux如何查看文件的总大小?

    在Linux中 查看文件的总大小的方法分别包括 stat命令 wc命令 du命令 ls命令 接下来通过这篇文章为大家详细的介绍一下 Linux中内置了多种命令来查看文件大小 具体请看下文 1 stat命令 stat命令用于显示文件的状态信息
  • 宽带无线通信知识点整理_第二章_信道模型

    目录 1 概述 1 1 信道模型 1 2 调制信道模型 1 3 信道参数和影响因素 2 不考虑空间特性的信道模型 全向天线 2 1 信道的基本特质 2 1 1 多经 2 1 2 多普勒频移 Doppler Shift 2 2 3 衰落计算实

随机推荐

  • 顶刊TIP 2022|双管齐下,中科院自动化所提出用于行为识别的姿势外观联合建模网络PARNet

    论文标题 Pose Appearance Relational Modeling for Video Action Recognition 论文链接 https ieeexplore ieee org document 9986038 代码
  • 解决加速c/c++编译运行速度的问题办法

    自从换了新电脑后 编译的时候就从来没有快过 就算编译很快 链接的时候也得等 别人题都已经交上去了 我还没从debug后重新编译的噩梦中逃脱出来 直到我发现了后台的qq电脑管家一直在 建议把所有的第三方杀毒 管家之类的所有软件全部关掉 通通关
  • 攻防世界-Reverse-666(图解详细)

    自述 这道题对于新手来说还是比较经典的 把逆向与python脚本的编写联系了起来 因为刚开始我没有学python 一遇到脚本什么的就很懵 学了半个月python后 我对做题有个更深的认识 记录一下 解题 把文件放入IDA 找到main函数
  • java.lang.IllegalArgumentException: Param ‘serviceName‘ is illegal, serviceName is blank

    目录 问题描述 解决过程 使用的 cloud alibaba 2021 0 1 0 springboot2 6 8版本 问题描述 使用Nacos作为配置中心 然后启动报错了 而且还是报的两种错误 如下 java lang IllegalAr
  • avalon绑定属性总结

    model 所有非 属性 event 事件对象 1 作用域圈定 ms controller 按着就近原则自下而上扫描DOM树 ms important 仅扫描本节点及之下作为扫描区 ms skip 使绑定失效 2 ms duplex双向绑定
  • Android实现底部导航栏方法(Navigation篇)

    Navigation实现底部导航栏 前言 导入和基本使用 导入 基础使用 创建nav文件 编辑Nav文件 添加页面 代码版 添加页面 图解版 创建导航动作 action 创建action 代码版 创建action 图解版 编辑action参
  • 机器人学习路线

    前言 我觉得机器人和人工智能最大的区别在于是否要和物理世界进行交互 传感器是和物理世界交互的基础 机器人学里公认的难题是在物理世界中实现类人的活动能力 莫拉维克悖论 机器人学的核心问题是做好和物理世界的交互 处理与物理世界的交互的学科分为三
  • 计算机内部通常用几进制来表示程序和数据,计算机内部运行和处理的数据是几进制...

    计算机内部运行和处理的数据是二进制 原因 1 计算机是由逻辑电路组成 逻辑电路通常只有两个状态 开关的接通与断开 这两种状态正好可以用1和0表示 2 二进制中只使用0和1两个数字 传输和处理时不易出错 因而可以保障计算机具有很高的可靠性 本
  • Map和Set详解

    一 二叉搜索树搜索树 1 二叉搜索树的概念 二叉搜索树又称二叉排序树 它或者是一棵空树 或者是具有以下性质的二叉树 若它的左子树不为空 则左子树上所有节点的值都小于根节点的值 若它的右子树不为空 则右子树上所有节点的值都大于根节点的值 它的
  • Vue引入qrcode.js实现生成二维码

    最近Vue音视频项目应用层中有JavaScript生成二维码的需求 所以记录下整个二维码生成的步骤 1 vue qr是基于qrcode js封装的vue库 可以动态生成二维码 并且可以自定义样式 npm install vue qr sav
  • unity中异步加载场景时灯光变暗的问题

    记得以前遇到到这种情况 然后 经久不用 忘记了 这次记录一下 加深印象 你会发现跳转场景后 后者的游戏场景的灯光会变暗 而且还改不回原来的效果 这里需要对场景进行灯光烘培 具体操作 Window Lighting Settings 取消勾选
  • python处理复杂excel_Python实现Excel的10个常用操作!干货满满(建议收藏)

    自从学了Python后就逼迫自己不用Excel 所有操作用Python实现 直接进入正题 数据是网上找到的销售数据 长这样 一 关联公式 Vlookup vlookup是excel几乎最常用的公式 一般用于两个表的关联查询等 所以我先把这张
  • 使用TypeScript 搜索JSON的简单方法

    使用TS 写了一个简单的 搜索JSON数组的方法 分享给大家 感觉效率一般 有方法的朋友请拍砖 public static JsonQuery arr Array
  • 浏览器滚动条样式

    webkit scrollbar 滚动条整体部分 webkit scrollbar thumb 滚动条里面的小方块 能上下左右移动 取决于是垂直滚动条还是水平滚动条 webkit scrollbar track 滚动条的轨道 里面装有thu
  • python找假硬币二分法_python – OpenCV硬币检测和自动结果检查

    我正在开展一个硬币识别项目 我遇到的第一件事就是从图像中提取正确的硬币 即使是非常简单的图像也是如此 硬币检测有很多好的工作方法 但我认为所有这些都需要在申请后进行人工检查 我测试了其中两个 cv2 HoughCircles和阈值与find
  • 如何新建一个vue项目?

    截止目前新建一个vue项目 有多种选择 比如 1 vue版本 vue2 vue3 2 脚手架 vue cli vue cli vite 其中 Vue cli Vue 一堆的js插件 vue cli是Vue cli的最新版本 不同vue cl
  • DDL与DML语句

    1 DDL语句 SQL语句 结构化查询语句 使用SQL与数据库 沟通 完成相应的数据库操作 l DDL 数据定义语言 用来维护数据库对象 1 1 创建表 CREATE 创建表 演示 创建员工表 CREATE TABLE employee i
  • Python下载pandas库失败的解决办法

    使用pip install pandas 总是失败 在网上找了好几个办法都不行 最后解决办法 pip default timeout 1000 install pandas 完美解决
  • package.json版本号符号^和~前缀的区别

    开发中经常会使用npm install 安装依赖包 经常会看到 符号和 符号 现将二者的区别总结如下 devDependencies babel runtime 7 12 0 dcloudio types dcloudio uni auto
  • 查找——二叉排序树(C语言实现)

    二叉排序树 二叉查找树 树表的提出 1 如何在一个大型的数据集合上进行动态查找 1 顺序查找 不要求元素的有序性 插入 删除的性能是O 1 查找性能是O n lt 需要一个个比较 gt 2 折半查找 查找性能是O log2n 为保证元素的有