【数据结构】二叉搜索(查找/排序)树

一、二叉搜索树基本概念

1、定义

二叉搜索树,又称为二叉排序树二叉查找树,它满足如下四点性质:

1)空树是二叉搜索树;
2)若它的左子树不为空,则左子树上所有结点的值均小于它根结点的值;
3)若它的右子树不为空,则右子树上所有结点的值均大于它根结点的值;
4)它的左右子树均为二叉搜索树;

 如上图所示:二叉搜索树的任何一棵子树,它的根结点的值一定大于左子树所有结点的值,且一定小于右子树所有结点的值。如果对二叉搜索树进行中序遍历,我们可以发现,得到的序列是一个递增序列,上述的遍历结果为[1,2,3,4,5,6,7,8]。

如果要查找4,只需要从根结点比较查找3次就能找到,可以显著提高搜索的速度

二、二叉搜索树基础操作

1、查找算法

(1)查找原理

在二叉搜索树中查找某个数是否存在,存在返回 true,不存在返回 false

对于要查找的数 val ,从根结点出发,总共四种情况依次判断:

1)若二叉搜索树为空树,直接返回 false;

2) val 的值 等于 树根结点的值,则直接返回 true;

3) val 的值 小于 树根结点的值,说明 val 对应的结点不在根结点,也不在右子树上,需要在左子树上查找,递归返回左子树的查找结果;

4) val 的值 大于 树根结点的值,说明 val 对应的结点不在根结点,也不在左子树上,需要在右子树上查找,递归返回右子树的查找结果;

(2)查找算法源码

① 结点源码

struct TreeNode {
	int val;
 	struct TreeNode *left;
 	struct TreeNode *right;
	TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
  };

② 查找算法源码 (深度优先,递归查找)

bool BSTFind(TreeNode* root, int val) 
{
    if (root == nullptr) {
        return false;
    }
    if (root->val == val) {
        return true;
    }
    if (val < root->val) {
        return BSTFind(root->left, val);
    }
    else {
        return BSTFind(root->right, val);
    }
}

2、插入算法

(1)插入原理

将给定的值 val 生成结点后,插入到树上的某个位置,并且保持这棵树还是二叉搜索树。对于要插入的值 val ,从根结点出发,总共四种情况依次判断:

1)若为空树,则创建一个值为 val 的结点并且返回根结点;

2) val 的值 等于 树根结点的值,无须执行插入,直接返回根结点;

3) val 的值 小于 树根结点的值,那么插入位置一定在 左子树,递归执行插入左子树的过程,并且返回插入结果作为新的左子树

4) val 的值 大于 树根结点的值,那么插入位置一定在 右子树,递归执行插入右子树的过程,并且返回插入结果作为新的右子树

(2) 插入源码

TreeNode* BSTInsert(TreeNode* root, int val) {
    if (root == nullptr) {
        root = new TreeNode(val);
        return root;
    }
    if (val == root->val) {
        return root;
    }
    if (val < root->val) {
        root->left = BSTInsert(root->left, val);
    }
    else {
        root->right = BSTInsert(root->right, val);
    }
    return root;
}

3、删除算法

(1)删除原理

删除值为 val 结点,从根结点出发,总共四种情况依次判断:

1)空树,不存在结点直接返回空树;

2) val 的值 小于 树根结点的值,则需要删除的结点一定不在右子树上,递归调用删除左子树的对应结点;

3) val 的值 大于 树根结点的值,则需要删除的结点一定不在左子树上,递归调用删除右子树的对应结点;

4) val 的值 等于 树根结点的值,相当于是要删除根结点,这时候又要分三种情况:

  • 当前树只有左子树,则直接将左子树返回,并且释放当前树根结点的空间;
  • 当前树只有右子树,则直接将右子树返回,并且释放当前树根结点的空间;
  • 当左右子树都存在时,需要在右子树上找到一个值最小的结点,替换新的树根,而其它结点组成的树作为它的子树;

(2)删除源码

由上述删除算法原理可知,删除结点之前可能还需要找最小结点,所以需要定义查找最小结点接口

int BSTFindMin(TreeNode* root) {
    if (root->left)
        return BSTFindMin(root->left);  
    return root->val;                   
}

查找根为 root ,值最小的那个结点的值,根据二叉搜索树的性质,如果左子树存在,则必然存在更小的值,递归搜索左子树,且最小值结点为叶子结点;如果左子树不存在,则根结点的值必然最小,直接返回。

删除根结点,并返回新根结点

//删除根结点并返回新根结点
TreeNode* Delete(TreeNode* root) {
    TreeNode* delNode, * retNode;
    if (root->left == nullptr) {
        delNode = root;
        retNode = root->right;
        delete delNode;
        delNode = nullptr;
    }
    else if (root->right == nullptr) {
        delNode = root;
        retNode = root->left;
        delete delNode;
        delNode = nullptr;
    }
    else {
        retNode = BSTFindMin(root->right);
        retNode->left = root->left;
        retNode->right = root->right;
        delete root;
        root = nullptr;
    }
    return retNode;
}
  • 如果左子树为空,则用右子树做为新的树根;
  • 如果右子树为空,则用左子树作为新的树根;
  • 否则,当左右子树都为非空时,利用 BSTFindMin ,从右子树上找出最小的结点,作为新的根。

删除指定值的结点

//删除指定结点
TreeNode* BSTDelete(TreeNode* root, int val) {
    if (nullptr == root) {
        return nullptr;                                  
    }
    if (val == root->val) {
        return Delete(root);                          
    }
    else if (val < root->val) {
        root->left = BSTDelete(root->left, val);      
    }
    else if (val > root->val) {
        root->right = BSTDelete(root->right, val);    
    }
    return root;                                      
}
  • 如果为空树,则直接返回空结点;
  • 如果需要删除的结点的值 等于 树根结点的值,则直接调用接口 Delete ;
  • 如果需要删除的结点的值 小于 树根结点的值,则需要删除的结点必定在左子树上,递归调用左子树的删除,并且将返回值作为新的左子树的根结点;
  •  如果需要删除的结点的值 大于 树根结点的值,则需要删除的结点必定在右子树上,递归调用右子树的删除,并且将返回值作为新的右子树的根结点;
  • 返回当前树的根结点;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/286966.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023年终总结与展望

2023年终总结 自2019年3月13日入驻CSDN&#xff0c;至今四年零九个月。截至2023年12月31日&#xff0c;CSDN博客已发原创博文120篇&#xff0c;粉丝9822位&#xff0c;访问量超过176万次。 2022年12月31日数据情况&#xff1a; 2023年12月31日数据情况&#xff1a; 从 年终数…

跟着cherno手搓游戏引擎【2】:日志系统spdlog和premake的使用

配置&#xff1a; 日志库文件github&#xff1a; GitHub - gabime/spdlog: Fast C logging library. 新建vendor文件夹 将下载好的spdlog放入 配置YOTOEngine的附加包含目录&#xff1a; 配置Sandbox的附加包含目录&#xff1a; 包装spdlog&#xff1a; 在YOTO文件夹下创建…

再见2023,你好2024(附新年烟花python实现)

亲爱的朋友们&#xff1a; 写点什么呢&#xff0c;我已经停更两个月了。2023年快结束了&#xff0c;时间真的过得好快&#xff0c;总要写点什么留下纪念吧。这一年伴随着许多挑战和机会&#xff0c;给了我无数的成长和体验。坦白说&#xff0c;有时候我觉得自己好像是在时间的…

一起学docker(四)| 数据卷 + 简单应用部署(MySQL,Tomcat,Nginx,Redis)

Docker 容器数据卷 Docker容器产生的数据&#xff0c;如果不备份&#xff0c;那么当容器实例删除后&#xff0c;容器内的数据也就消失了。需要对数据进行持久化。 为了保存docker中的数据&#xff0c;可以使用数据卷。 是什么 卷就是目录或文件&#xff0c;存在于一个或多个…

HUAWEI华为荣耀MagicBook X 15酷睿i5-10210U处理器集显(BBR-WAH9)笔记本电脑原装出厂Windows10系统

链接&#xff1a;https://pan.baidu.com/s/1YVcnOP5YKfFOoLt0z706rg?pwdfwp0 提取码&#xff1a;fwp0 MagicBook荣耀原厂Win10系统自带所有驱动、出厂主题壁纸、系统属性专属LOGO标志、Office办公软件、华为/荣耀电脑管家等预装程序 文件格式&#xff1a;esd/wim/swm 安装…

深度学习|10.5 卷积步长 10.6 三维卷积

文章目录 10.5 卷积步长10. 6 三维卷积![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/b5bfa24f57964b0f81f9602f5780c278.png) 10.5 卷积步长 卷积步长是指每计算一次卷积&#xff0c;卷积移动的距离。 设步长为k&#xff0c;原矩阵规模为nxn&#xff0c;核矩阵…

Python 实现给 pdf 文件自动识别标题并增添大纲

一、背景&#xff1a; 客户方提供过来一个开放平台的pdf文档&#xff0c;文档里有几十个接口&#xff0c;没有大纲和目录可以定位到具体内容&#xff0c;了解整体的API功能&#xff0c;观看体验极度差劲&#xff0c;所以想使用Python代码自动解析pdf文档&#xff0c;给文档增添…

【Spring实战】17 REST服务介绍

文章目录 1. 为什么出现2. 拥有哪些优势3. Spring中的应用4. spring-boot-starter-data-rest总结 REST&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;通常用于设计网络应用程序的服务接口。RESTful 服务是基于 REST 原则构建的网络服…

手机录屏没有声音?让你的录屏有声有色

“有人知道手机录屏怎么录声音吗&#xff1f;今天录制了一个小时的直播视频&#xff0c;后面查看的时候发现没有声音&#xff0c;真的非常崩溃&#xff0c;想问问大家有没有办法&#xff0c;解决这个问题。” 在手机录屏的过程中&#xff0c;有时候我们可能会面临录制视频没有…

socket实现视频通话-WebRTC

最近喜欢研究视频流&#xff0c;所以思考了双向通信socket&#xff0c;接下来我们就一起来看看本地如何实现双向视频通讯的功能吧~ 客户端获取视频流 首先思考如何获取视频流呢&#xff1f; 其实跟录音的功能差不多&#xff0c;都是查询电脑上是否有媒体设备&#xff0c;如果…

杰发科技AC7840——Eclipse环境DMA注意事项

0.序 用 户 使 用 DMA 时 &#xff0c; 所 有 DMA 搬 运 的 SRAM 数 据 都 必 须 存 放 在 SRAM_U 区 (0x20000000~0x2000EFFF) 。 1. 修改办法 第一步&#xff1a; RAM定义 /* Specify the memory areas */ MEMORY {FLASH (rx) : ORIGIN 0x00000000, LENGT…

多功能号卡推广分销管理系统 流量卡推广分销网站源码

一套完善&#xff0c;多功能&#xff0c;的号卡分销系统&#xff0c;多接口&#xff0c;包括运营商接口&#xff0c;无限三级代理&#xff0c;最简单易用的PHP~ 目前市面上最优雅的号卡系统&#xff01;没有之一 软件架构说明 环境要求php7.3以上&#xff08;建议低于8.0&…

面试题理解深层次的数组名

目录 引言 一&#xff1a;一维数组 举例如下 1.铺垫知识 数组名是数组首元素的地址&#xff0c;但是有两个特殊情况 &#xff08;1&#xff09;sizeof(数组名) &#xff08;2&#xff09;&数组名 2.分析讲解上述代码结果 2.字符数组 举例一如下 1.知识铺垫 …

Python内置库os和sys的常用方法汇总

更多Python学习内容&#xff1a;ipengtao.com Python是一门强大的编程语言&#xff0c;具有丰富的标准库&#xff0c;其中包括os和sys两个常用模块。os模块用于与操作系统交互&#xff0c;提供了许多文件和目录操作的方法&#xff0c;而sys模块用于与Python解释器进行交互&…

OceanBase入选Gartner®云数据库管理系统魔力象限“荣誉提及”

近日&#xff0c;全球IT市场研究和咨询公司Gartner发布最新报告《Magic Quadrant™ for Cloud Database Management Systems》&#xff08;全球云数据库管理系统魔力象限&#xff09;。全自研分布式数据库 OceanBase 入选“荣誉提及”&#xff0c;2022 年推出的云数据库 OB Clo…

uniapp---安卓真机调试提示检测不到手机【解决办法】

最近在做APP&#xff0c;由于华为手机更新过系统&#xff0c;再次用来调试APP发现就不行了。下面给出具体的解决方法&#xff1a; 第一步&#xff1a;打开【允许开发人员选项】 找到【设置】点击【关于手机】找到【版本号】点击7次或多次&#xff0c;允许开发人员选项。 第二…

性能优化:Spark SQL中的谓词下推和列式存储

Apache Spark是一个强大的分布式计算框架&#xff0c;Spark SQL是其一个核心模块&#xff0c;用于处理结构化数据。性能优化是大数据处理中的一个关键问题&#xff0c;本文将深入探讨Spark SQL中的两个性能优化技术&#xff1a;谓词下推&#xff08;Predicate Pushdown&#xf…

Ps:应用图像

Ps菜单&#xff1a;图像/应用图像 Image/Apply Image 应用图像 Apply Image命令可以将图像的内容&#xff08;作为“源”&#xff09;叠加到另一图像&#xff08;作为“目标”&#xff09;上&#xff0c;同时提供了控制混合的详细选项。 “应用图像”命令在图像合成、图层蒙版和…

彻底理解前端安全面试题(2)—— CSRF 攻击,跨站请求伪造攻击详解,建议收藏(含源码)

前言 前端关于网络安全看似高深莫测&#xff0c;其实来来回回就那么点东西&#xff0c;我总结一下就是 3 1 4&#xff0c;3个用字母描述的【分别是 XSS、CSRF、CORS】 一个中间人攻击。当然 CORS 同源策略是为了防止攻击的安全策略&#xff0c;其他的都是网络攻击。除了这…

音视频通信

文章目录 一、音视频通信流程二、流媒体协议1、RTSP2、RTMP3、HLS4、WebRTC 一、音视频通信流程 音视频通信完整流程有如下几个环节&#xff1a;采集、编码、前后处理、传输、解码、缓冲、渲染等。 每一个细分环节&#xff0c;还有更细分的技术模块。比如&#xff0c;前后处…