C++实现基础二叉搜索树(并不是AVL和红黑树)

本次实现的二叉搜索树并不是AVL数和红黑树,只是了解流程和细节。

目录

  • 二叉搜索树的概念
  • K模型二叉搜索树的实现
    • 二叉搜索树的架构
    • insert插入
    • find 查找
    • 中序遍历Inorder
    • 删除earse
      • 替换法的思路
      • 情况一 :假如要删除节点左边是空的。
        • 在左边时
        • 在右边时
      • 情况二:假如要删除节点右边是空的。
        • 是父亲的右边时
        • 是父亲的左边时
      • 情况三:两边都有值
        • 左边
        • 右边
        • 代码实现

二叉搜索树的概念

二叉搜索树并不是单纯存储数据。所以他有规则:
①.左子树比根小,右子树比根大。

②.搜索二叉树不建议用递归。

二叉搜索树一定要遵循这个规律!否则他都不能算是二叉搜索树!

K模型二叉搜索树的实现

二叉搜索树的架构

我们之前也学过二叉树,二叉树的结构是节点里面放了左右指针和值,所以节点就是一下结构。 而二叉树的本身就是又一个根节点连接起来的

template<class T>
struct BinarySearchTreeNode
{BinarySearchTreeNode(T& key):_key(key), _left(nullptr), _right(nullptr){}T _key;BinarySearchTreeNode* _left;BinarySearchTreeNode* _right;
};template<class T>class BinarySearchTree{public:typedef BinarySearchTreeNode<T> Node;		private:Node* _root=nullptr;};

insert插入

插入一定要遵循规则:
①.左子树比根小,右子树比根大。
不是这个规则都不是二叉搜索树。

(1). 当你插入第一个值的时候,他就是根,所以我们要特殊处理,当_root==nullptr时,要把第一个插入的值变成根。
(2).除第一个值之后的值就要遵行规则。

bool insert(T& x)
{if (_root == nullptr){Node* noeNode = new Node(x);_root = noeNode;return true;}Node* cur = _root;Node* parent = cur;while (cur){if (cur->_key < x){//大于在右边parent = cur;cur = cur->_right;}else if (cur->_key > x){//小于在左边parent = cur;cur = cur->_left;}else{//等于,二叉搜索树不允许冗余,所以直接返回false。return false;}}Node* newNode = new Node(x);if (newNode->_key > parent->_key)parent->_right = newNode;elseparent->_left = newNode;return true;
}

find 查找

查找就很简单,只要把前面的代码复制一半,当查找到了,我们就返回true,到空了都没找到就返回false。

bool find(const T& x)
{Node* cur = _root;Node* parent = cur;while (cur){if (cur->_key < x){//大于在右边parent = cur;cur = cur->_right;}else if (cur->_key > x){//小于在左边parent = cur;cur = cur->_left;}else{//等于,找到了return true;}}return false;
}

中序遍历Inorder

中序遍历我们都很了解了,但是问题是,我们要把根传入,根一定是私有的,你在类外访问不了。这个时候我们就可以套一层。

publicvoid Inorder()
{_Inorder(_root);cout << endl;
}
private:void _Inorder(Node* _root){if (_root == nullptr) return;_Inorder(_root->_left);cout << _root->_key<< " ";_Inorder(_root->_right);}Node* _root=nullptr;

删除earse

删除其实很麻烦,有很多种情况。因为二叉搜索数一定是满足规则的,所以我们删除不能混乱了规则,而是继续保持规则。所以我们要用替换法,保证规则不乱

替换法的思路

因为我们要保证规则不乱,那么我们可以用替换法,让左树的最大值/右树的最小值与当前值替换,因为当前节点的左边一定比他小,右边一定比他大,那么当我们用左边最大值,替换了当前节点,也不会改变规则;右边同理。

情况一 :假如要删除节点左边是空的。

在左边时

假如我要删除9这个节点。并且左侧是空,那么我们是不是可以直接让他父亲的左边指向他的右边?思考一下!

为什么?左侧为空,当前删除节点的左侧一定是什么都没有的,右边可有可无,但是右边没有也没关系,一样置空,有的话,我们就需要让他的父亲链接他的孩子。
在这里插入图片描述
并且我们发现并不用替换法,就可以直接链接后删除。
在这里插入图片描述

在右边时

其实在右边也是一样的,只不是我们要特殊判断一下,删除节点时父亲的左边还是右边,方便我们链接。
在这里插入图片描述

情况二:假如要删除节点右边是空的。

是父亲的右边时

那么他右边一定是没有值的,左边的值可有可无,那么我们就需要让它的父亲指向他的左值就可以了。
在这里插入图片描述

是父亲的左边时

在这里插入图片描述

情况三:两边都有值

如果这棵树是这样的,那么我要删除9怎么做呢?就需要替换法,我们需要找左边最大值或者右边最小值,我们假设要找是右边最小值
在这里插入图片描述

从当前节点开始找,右边最小值是10(蓝色标记)。

问:为什么要从当前节点找,而不是从根开始?
答:如果从根开始找,你会发现,当我们交换后,不满足条件了。图中右边最小值是13,如果换到最左边那就不满足二叉搜索的要求了,所以要从当前节点找,因为当前节点的右边跟当前这个位置换一定是比大,比其他节点小的。

在这里插入图片描述
当我们都找到了,我们就要用交换法。将两个值交换后,左边最小的那个节点就是我们要删除的。那么我们就需要把最小节点的右边给它的右边。
在这里插入图片描述

左边

这里给大家道个歉,因为数字太过紧凑,所以凑不出数,只能让整型和浮点数混合了,在实际场景中是不可能有的,只是举个例子

假设我们交换后,发现要删除的节点右边还有值,

问题:我怎么让被删除节点的父亲知道是左边还是右边的节点间接我的右节点呢
答:需要判断一下,如果被删除的节点是父亲的左边,就需要让左边指向被删的右边,如果是父亲的右边就让父亲的右边指向被删的右边。

在这里插入图片描述
在这里插入图片描述

右边

这种情况,就是他在父亲的右边,所以我们需要让父亲的右边链接被删的右边。
在这里插入图片描述

代码实现

虽然删除的代码很复杂,但是要注意的细节很多。
(1).在我们找到了当前被删节点,情况三的时候,能不能让Node* rightMinParent = nullptr;? 答:不可以,因为当我们删除这种情况的时候,就会导致空指针访问,因为循环我们没有进去,但是链接值的时候,就会导致空指针访问。

(2).在我们交换后,能不能递归把他删了?不能!我问你交换后还满足二叉搜索数的要求吗?不满足,你永远都不会找到!

在这里插入图片描述

		bool erase(const T& x){Node* cur = _root;Node* parent = cur;while (cur){if (cur->_key < x){//大于在右边parent = cur;cur = cur->_right;}else if (cur->_key > x){//小于在左边parent = cur;cur = cur->_left;}else{//等于,找到了if (cur->_left == nullptr){//没有值直接删,把右边给父亲if (cur == parent->_left){parent->_left = cur->_right;delete cur;}else if(cur == parent->_right){parent->_right = cur->_right;delete cur;}}else if (cur->_right == nullptr){if (cur == parent->_left){parent->_left = cur->_left;delete cur;}else if (cur == parent->_right){parent->_right = cur->_left;delete cur;}}else{Node* rightMin = cur->_right;Node* rightMinParent = cur;//这里要让父亲是cur,删根的时候就会出问题while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}std::swap(cur->_key, rightMin->_key);if (rightMinParent->_left == rightMin)rightMinParent->_left = rightMin->_right;elserightMinParent->_right = rightMin->_right;delete rightMin;}return true;}}return false;}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

文心智能体,零代码构建情感表达大师智能体

前言 随着智能体技术的突飞猛进&#xff0c;各行各业正迎来前所未有的变革与机遇。智能体&#xff0c;作为人工智能领域的重要分支&#xff0c;以其自主性、智能性和适应性&#xff0c;正逐步渗透到我们生活的每一个角落&#xff0c;成为推动社会进步和科技发展的新动力。 为了…

软考 系统架构设计师系列知识点之杂项集萃(20)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;19&#xff09; 第28题 在单元测试中&#xff0c;&#xff08; &#xff09;。 A. 驱动模块用来调用被测模块&#xff0c;自顶向下的单元测试中不需要另外需要编写驱动模块 B. 桩模块用来模拟被…

visual studio 2022 ssh 主机密钥算法失败问题解决

 Solution - aengusjiang 问题&#xff1a; I follow the document, then check sshd_config, uncomment“HostKey /etc/ssh/ssh_host_ecdsa_key” maybe need add the key algorithms: #HostKeyAlgorithms ssh-ed25519[Redacted][Redacted]rsa-sha2-256,rsa-sha2-512 Ho…

Redis常用命令——String篇

前面我们讲解了一些 Redis 的全局命令&#xff08;Redis常用基本全局命令&#xff09;。所谓全局命令&#xff0c;就是可以匹配任意一个数据结构进行使用。但是不同的数据结构&#xff0c;也有自己的操作命令。本篇文章主要讲解的是 String 的操作命令&#xff0c;希望会对你有…

ClickHouse课件

列式存储数据库&#xff1a;hbase clickhouse 简介 ClickHouse入门 ClickHouse是俄罗斯的Yandex于2016年开源的列式存储数据库&#xff08;DBMS&#xff09;&#xff0c;使用C语言编写&#xff0c;主要用于在线分析处理查询&#xff08;OLAP&#xff09;&#xff0c;能够使用…

2024年电工杯B题论文首发+问题一论文代码分享

问题一论文代码链接&#xff1a;https://pan.baidu.com/s/1kDV0DgSK3E4dv8Y6x7LExA 提取码&#xff1a;sxjm --来自百度网盘超级会员V5的分享 基于数据分析的大学生平衡膳食食谱的优化设计及评价 摘要 大学时期不仅是学术学习和身体成长的关键阶段&#xff0c;更是青年学生…

supermind读写自选股的功能来了

python custom_sector() # 返回所有板块的dataframecustom_sector(板块1) # 返回 板块1 的属性和股票custom_sector(板块1, append, [000001.SZ]) # 增加板块1的股票列表custom_sector(板块1, pop, [000001.SZ]) # 移除板块1的股票custom_sector(板块1, remove) # 删除板块1zxg…

Hsql每日一题 | day03

前言 就一直向前走吧&#xff0c;沿途的花终将绽放~ 题目&#xff1a;打折日期交叉问题 如下为平台商品促销数据&#xff1a;字段为品牌&#xff0c;打折开始日期&#xff0c;打折结束日期 brand stt edt oppo,2021-06-05,2021-06-09 oppo,2021-06-11,2021-06-21 vivo,…

Java中流的概念细分

按流的方向分类&#xff1a; 输入流&#xff1a;数据流向是数据源到程序&#xff08;以InputStream、Reader结尾的流&#xff09;。 输出流&#xff1a;数据流向是程序到目的地&#xff08;以OutputStream、Writer结尾的流&#xff09;。 按处理的数据单元分类&#xff1a; 字…

PVE 虚拟机环境下删除 local-lvm分区

1、删除逻辑卷 lvremote pve/data 2、扩展逻辑卷 lvextend -l 100%FREE -r pve/root 3、 修改存储目录内容 点击 Datacenter - Storage &#xff08;1&#xff09;删除local-lvm分区 &#xff08;2&#xff09;编辑local分区&#xff0c;在内容一项中勾选所有可选项。

mysql 两个不同字段的表导入数据

下面这个场景就是A表的字段和B表的字段不一样&#xff0c;但是现在我想把b表中的数据导入到A表里面&#xff0c;下面是导入公式如下&#xff1a; 语法&#xff1a; 将SYS_ORG表中的数据导入到sys_depart&#xff0c;但是这两个表的字段不一样&#xff0c;在()里面填写要新增数据…

Spring Boot 3.3 正式发布,王炸级更新,应用启动速度直接起飞!

最新消息&#xff0c;Spring Boot 一次性发布了 3 个版本&#xff1a; 3.3.0 3.2.6 3.1.13 Spring Boot 3.3 正式发布了&#xff0c;3.1.x 在前几天也停止维护了。 最新的支持版本如下&#xff1a; 从路线图可以看到每个版本的终止时间&#xff0c;每个版本的生命周期只有…

安徽大学数学科学学院教授陈昌昊

男&#xff0c;本&#xff08;2005-2009&#xff09;、硕&#xff08;2009-2012&#xff09;学位都在湖北大学获得&#xff0c;博士学位在芬兰获得&#xff08;2012-2016&#xff09;&#xff0c;博士后分别在澳大利亚&#xff08;2016-2019&#xff09;、香港&#xff08;2020…

vue3中el-form表单校验,再点击提交按钮的时候通过校验才进行提交

vue3中el-form表单校验&#xff0c;再点击提交按钮的时候通过校验才进行提交 一、前言1、案例 一、前言 在 Vue 3 中&#xff0c;可以使用 Element UI 的 <el-form> 组件配合 <el-form-item> 来实现表单的必填项校验&#xff0c;并在提交时根据校验结果来决定是否…

clickhouse 中的数组(array)和元组(Tuple)—— clickhouse 基础篇(二)

文章目录 数组判断是否为空计算数组长度获取数组元素判断某个元素是否存在数组切片数组元素展开数组元素去重删除连续重复元素连接多个数组数组倒序数组拍平数组元素映射数组元素过滤数组聚合分析计算数组交集计算数组并集计算数组差集SQL 子查询进行集合操作 元组创建元组获取…

LeetCode刷题之HOT100之二叉树的直径

2024/5/25 阴天。这几天睡眠质量都非常好&#xff0c;一切似乎都在慢慢上升。先把题做了 1、题目描述 2、逻辑分析 题目要求就是给一个二叉树&#xff0c;求出两个节点之间的最大长度即为二叉树的直径。怎么做呢&#xff1f;我想不出来。看一下题解吧。题解给出的解法是深度优…

Swagger2 和 Swagger3 的不同

Swagger2 和 Swagger3 的不同 SpringBoot 整合 Swagger3 和 Swagger2 的主要区别如下&#xff1a; 区别一&#xff1a;引入不同的依赖 如果使用的是 Swagger 3 <dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter<…

Linux——Docker容器虚拟化平台

安装docker 安装 Docker | Docker 从入门到实践https://vuepress.mirror.docker-practice.com/install/ 不需要设置防火墙 docker命令说明 docker images #查看所有本地主机的镜像 docker search 镜像名 #搜索镜像 docker pull 镜像名 [标签] #下载镜像&…

学习java第八十天

ApplicationContext有哪些常见实现&#xff1f; FileSystemXmlApplicationContext容器从XML文件加载bean的定义。XML bean配置文件的完整路径必须提供给构造函数。 ClassPathXmlApplicationContext容器也从XML文件加载bean的定义。这里&#xff0c;你需要正确设置classpath因…

mybatis-plus 优雅的写service接口中方法(3)

多表联查 上文讲过了自定义sql &#xff0c;和wrapper的使用&#xff0c;但是我们可以发现 我们查询的都是数据库中的一张表&#xff0c;那么怎么进行多表联查呢&#xff0c;当然也是用自定义sql来进行实现 比如说 查询 id 为 1 2 4 的用户 并且 地址在北京 的 用户名称 普…