从零开学C++:二叉搜索树

引言:在本篇博客当中,我们会将关于二叉树的进阶结构——二叉搜索树,强大的搜索效率让它在数据结构当中变得十分重要,让我们一起来进行学习吧!

更多有关C++的知识详解可前往个人主页:计信猫

一,二叉搜索树的概念

        二叉搜索树的概念其实很简单,首先它一定满足成为一颗二叉树的基本条件,其次值比根节点小的储存在左子树,值比根节点大的储存在右子树,同时它的左右子树也为二叉搜索树。如图就是一颗简单的二叉搜索树

二,二叉搜索树的创建

        既然我们想创建一颗二叉搜索树,那么首先我们就应该创建一个二叉搜索树节点结构体(我们称为Node),如下代码所示:

template<class k>
class Node
{
public:Node(const k& key):_left(nullptr), _right(nullptr), _key(key){}Node* _left;Node* _right;k _key;//key为所储存的值
};

        此后我们还应该创建一个结构体专门用于二叉搜索树的遍历,数据操作,代码如下:

template<class k>
class BSTree
{
public:using Node = Node<k>;Node* _root = nullptr;
};

三,二叉搜索树的数据操作函数

1,插入数据

        在二叉搜索树中,我们想插入一个值其实就非常简单了,我们分为两种情况:

        情况一:当二叉搜索树为一个空树时,那么我们就直接创建一个节点并且将这个节点赋值给_root即可。

        情况二:即不为空树时,那么我们只需要根据二叉搜索树的规则遍历到二叉树的根节点,再把数据插入即可。

        所以我们的代码如下:

//插入数据
bool insert(const k& key)
{//情况一:根节点为空if (_root == nullptr){_root = new Node(key);return true;}//情况二:根节点不为空else{//比根节点大的放左边,比根节点小的放右边Node* cur = _root;Node* parent = nullptr;//cur遍历到根节点while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{return false;}}cur = new Node(key);//比父节点小就插入左边,反之则插入右边if (parent->_key > key){parent->_left = cur;}else{parent->_right = cur;}return true;}

 2,查找数据

        该函数的作用是查找二叉搜索树中是否存在值key,如果在遍历的过程中找到了值key,那么就返回true,若未找到值key,就返回false。那么代码如下:

//查找数据
bool find(const k& key)
{Node* cur = _root;while (cur){if (cur->_key > key)//比父节点大就往右走{cur = cur->_right;}else if (cur->_key < key)//比父节点小就往左走{cur = cur->_left;}else//相等就返回true{return true;}}return false;
}

 3,删除数据

        删除数据函数在本篇博客中就相对复杂,但没事,我将分情况来进行一一地讲解。

(1)删除的节点左右子树都为空

        这种情况就非常简单,删除这种叶子节点(cur)我们只需要将其父节点的左右指针指向空,然后delete掉这个叶子节即可,如下图所示:

        而该种情况可以被我们直接归类为情况(2)或情况(3) 。

(2)删除的节点左子树不为空,右子树为空

        当我们遇到这种情况的时候,我们就可以将其父节点(parent)与这个节点(cur)的左孩子相连,但连接的时候我们同时需要判断这个节点与父节点的左右关系如果被删除节点在父节点的左边,那么我们就应该将该节点的左子树插入到父节点的左边,反之我们则插入父节点的右边。如下图所示:

        可一旦当我们遇到如下图的情况就要进行特殊处理:

        其实处理办法也很简单,我们只需要根节点的左孩子赋值给_root,然后再删除cur节点即可。所以该情况下处理的代码如下:

else if (cur->_right == nullptr)//cur的右边为空
{if (cur == _root)//特殊情况{_root = cur->_left;}else{if (parent->_left == cur)//左孩子被删除{parent->_left = cur->_left;}else//右孩子被删除{parent->_right = cur->_left;}}delete cur;return true;
}

(3)删除的节点左子树为空,右子树不为空

        那么这种情况其实就可以直接类比到情况(2)了,此时我们就可以直接展示代码:

if (cur->_left == nullptr)//cur的左边为空
{if (cur == _root)//特殊情况{_root = cur->_right;}else{if (parent->_left == cur)//左孩子被删除{parent->_left = cur->_right;}else//右孩子被删除{parent->_right = cur->_right;}}delete cur;return true;
}

(4)删除的节点左子树和右子树都不为空

        这种情况是最麻烦的一种,但是不用担心,静下心来慢慢理解,你会发现易如反掌。那让我们以下图为例子:

        那么解决这种问题,我们就会用到一种方法,叫做替换法替换法的含义是找到左子树的最右节点或者右子树的最左节点,来替换掉要删除的节点,再删除需要被删除的节点。语言听着很晦涩,那么我们以图来说明!

        这样,一个节点就成功被我们删除了!但是要注意,连接节点的时候还是要进行判断,若被删除的节点是在其父节点的左边,那么替换的节点也必须被连接在父节点的左边,同理,右边也是一样的。所以我们的代码如下:

//删除数据
bool erase(const k& key)
{Node* cur = _root;Node* parent = nullptr;//使用cur先遍历到要删除的节点的位置while (cur){if (key > cur->_key){parent = cur;cur = cur->_right;}else if (key < cur->_key){parent = cur;cur = cur->_left;}else{//相等,进行删除操作if (cur->_left == nullptr)//cur的左边为空{if (cur == _root){_root = cur->_right;}else{if (parent->_left == cur)//左孩子被删除{parent->_left = cur->_right;}else//右孩子被删除{parent->_right = cur->_right;}}delete cur;return true;}else if (cur->_right == nullptr)//cur的右边为空{if (cur == _root){_root = cur->_left;}else{if (parent->_left == cur)//左孩子被删除{parent->_left = cur->_left;}else//右孩子被删除{parent->_right = cur->_left;}}delete cur;return true;}else//左右均不为空,使用替换法删除:左子树的最大值或者右子树的最小值{Node* replace = cur->left;Node* replaceparent = cur;while (replace->_right){replaceparent = replace;replace = replace->_right;}cur->_key = replace->_key;if (replaceparent->_left == replace){replaceparent->_left = replace->_left;}else{replaceparent->_right = replace->_left;}delete replace;return true;}}}return false;
}

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

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

相关文章

无人机避障——4D 毫米波雷达 SLAM篇(一)

做无人机避障相关工作&#xff0c;3D毫米波避障测试顺利后&#xff0c;开始做4D毫米波雷达无人机避障遇到4D雷达点云需要进行处理的问题&#xff0c;查阅文献&#xff0c;发现以下这篇文章中的建图方法应该为后续思考的方向&#xff0c;特此将这个开源项目进行复现和学习&#…

《论分布式存储系统架构设计》写作框架,软考高级系统架构设计师

论文真题 分布式存储系统&#xff08;Distributed Storage System&#xff09;通常将数据分散存储在多台独立的设备上。传统的网络存储系统采用集中的存储服务器存放所有数据&#xff0c;存储服务器成为系统性能的瓶颈&#xff0c;也是可靠性和安全性的焦点&#xff0c;不能满…

vue3.0 + element plus 全局自定义指令:select滚动分页

需求&#xff1a;项目里面下拉框数据较多 &#xff0c;一次性请求数据&#xff0c;体验差&#xff0c;效果就是滚动进行分页。 看到这个需求的时候&#xff0c;我第一反应就是封装成自定义指令&#xff0c;这样回头用的时候&#xff0c;直接调用就可以了。 第一步 第二步&…

双十一好物清单分享?五款超值的数码好物分享!

双十一马上就来啦&#xff0c;大家是不是都等着在这个时候买点好东西呀&#xff1f;数码产品可是咱们生活里少不了的&#xff0c;能让咱们的生活更方便、更有意思。我这儿给大家挑了五款特别值的数码好东西&#xff0c;准备来跟大家分享分享&#xff01;快来看看有没有你中意的…

【JAVA基础】JAVA类的拷贝使用示例

文章目录 一、框架介绍二、性能对比三、易用性对比四、使用示例&#xff08;一&#xff09;Apache Commons BeanUtils 使用例子1、第一个例子&#xff1a;两个对象属性个数和名称一样&#xff0c;复制过程2、第二个例子&#xff1a;属性个数和名称不一样&#xff0c;复制过程 &…

UnityHub下载任意版本的Unity包

1)先打开 // 也可以采用2直接打开 2)也可以直接打开 下载存档 (unity.com) 3)关联起来UnityHub即可

Mora:多智能体框架实现通用视频生成

人工智能咨询培训老师叶梓 转载标明出处 尽管已有一些模型能够生成视频&#xff0c;但大多数模型在生成超过10秒的长视频方面存在局限。Sora模型的出现标志着视频生成能力的一个新时代&#xff0c;它不仅能够根据文本提示生成长达一分钟的详细视频&#xff0c;而且在编辑、连接…

【CSS】定位

static ( 默认 )relative ( 相对定位 )absolute ( 绝对定位 )fixed ( 固定定位 )sticky ( 粘性定位 ) 普通文档流&#xff1f;浮动也会让元素脱离文档流&#xff0c;如果不设置浮动所有元素都处于普通文档流中。普通文档流中元素框的位置由元素在HTML中的位置决定&#xff0c;块…

Redisson分布式锁的概念和使用

Redisson分布式锁的概念和使用 一 简介1.1 什么是分布式锁&#xff1f;1.2 Redisson分布式锁的原理1.3 Redisson分布式锁的优势1.4 Redisson分布式锁的应用场景 二 案例2.1 锁竞争案例2.2 看门狗案例2.3 参考文章 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff…

文献阅读——基于拉格朗日乘子的电力系统安全域边界通用搜索方法

摘要 为提升电力系统安全域(security region&#xff0c;SR)的构建效 率&#xff0c;提出一种基于拉格朗日乘子(Lagrange multiplier&#xff0c;LM) 的电力系统安全域边界(security region boundary&#xff0c;SRB)通用搜索方法。 首先&#xff0c;根据电力系统静态安全性问…

2024.9.25 数据分析学习

资料&#xff1a; 【开课吧哩堂】数据挖掘项目之用户流失预警系统_哔哩哔哩_bilibili 五万字 | Spark吐血整理&#xff0c;学习与面试收藏这篇就够了&#xff01;-腾讯云开发者社区-腾讯云 (tencent.com) 黑马程序员Spark全套视频教程&#xff0c;4天spark3.2快速入门到精通…

文件上传漏洞+CTF实例

解题思路 前端绕过 手动修改前端js代码进行绕过&#xff1a;右击-查看页面源代码-ctff进行位置定位-修改JavaScript函数 后端绕过 文件类型绕过&#xff08;Content-Type&#xff09; 常见MIME类型描述application/octet-stream 表示所有其他情况的默认值 text/plain表示文…

啥?Bing搜索古早BUG至今未改?

首先&#xff0c;大家先看下面的一个数学公式。 Γ ( z ) ∫ 0 ∞ t z − 1 e − t d t . \Gamma(z) \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)∫0∞​tz−1e−tdt. 看不懂&#xff1f;没关系&#xff0c;因为我也看不懂 这不是谈论的重点。 当你把鼠标光标移到公式的最开头&…

小程序-生命周期与WXS脚本

生命周期 什么是生命周期 生命周期&#xff08;Life Cycle&#xff09;是指一个对象从创建 -> 运行 -> 销毁的整个阶段&#xff0c;强调的是一个时间段。 我们可以把每个小程序运行的过程&#xff0c;也概括为生命周期&#xff1a; 小程序的启动&#xff0c;表示生命…

Github 2024-09-23 开源项目周报 Top15

根据Github Trendings的统计,本周(2024-09-23统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目6C++项目3C项目3HTML项目2PowerShell项目1TypeScript项目1JavaScript项目1Blade项目1PHP项目1Bootstrap 5: Web上开发响应式、移动优…

Kafka 面试题

参考&#xff1a; https://javabetter.cn/interview/kafka-40.htmlhttps://javaguide.cn/high-performance/message-queue/kafka-questions-01.html Kafka 架构 名词概念 Producer&#xff08;生产者&#xff09; : 产生消息的一方。 Consumer&#xff08;消费者&#xff09; …

影刀---实现我的第一个抓取数据的机器人

你们要的csdn自动回复机器人在这里文末哦&#xff01; 这个上传的资源要vip下载&#xff0c;如果想了解影刀这个软件的话可以私聊我&#xff0c;我发你 目录 1.网页对象2.网页元素3.相似元素组4.元素操作设置下拉框复选框滚动条获取元素的信息 5.变量6.数据的表达字符串变量列…

数据库主备副本物理复制和逻辑复制对比

数据库主从节点的数据一致性是保证数据库高可用的基本要求&#xff0c;各个数据库在实现方式上也各有异同。而主备复制的方式无外乎两种&#xff1a;物理复制和逻辑复制&#xff0c;本文简要对比下两种方式的不同&#xff0c;并分析下国产数据库是如何实现的。 1、数据库复制基…

初试Bootstrap前端框架

文章目录 一、Bootstrap概述二、Bootstrap实例1、创建网页2、编写代码3、代码说明4、浏览网页&#xff0c;查看结果5、登录按钮事件处理6、浏览网页&#xff0c;查看结果 三、实战小结 一、Bootstrap概述 大家好&#xff0c;今天我们将一起学习一个非常流行的前端框架——Boot…

Redis --- redis事务和分布式事务锁

redis事务基本实现 Redis 可以通过 MULTI&#xff0c;EXEC&#xff0c;DISCARD 和 WATCH 等命令来实现事务(transaction)功能。 > MULTI OK > SET USER "Guide哥" QUEUED > GET USER QUEUED > EXEC 1) OK 2) "Guide哥"使用 MULTI命令后可以输入…