【C++第十七章】二叉搜索树
【C++第十七章】二叉搜索树
二叉搜索树的介绍🧐
二叉搜索树又称二叉排序树,它可能是空树,也可能是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上的所有节点的值小于根节点的值
- 若它的右子树不为空,则右子树上的所有节点的值大于根节点的值
- 它的左右子树也分别为二叉搜索树
如我们将如下数组放入二叉搜索树中,会得到这样的结构,可以发现,它的中序是有序排列的。
int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};
二叉搜索树的查找🧐
从根开始比较查找,比根大就往右走,比根小就往左走,最多走树的高度次,如果走到空了还没找到,就是不存在。
参考代码:
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{return true;}}return false; }
二叉搜索树的插入🧐
当树为空时,直接增加新的节点,赋值给root指针,如果不为空,则按性质插入,小于根在左,大于根在右。
参考代码
bool Insert(const K& key) {if (_root == nullptr) //第一次插入{_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else{return false;}}//链接cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else if (parent->_key > key){parent->_left = cur;}return true; }
二叉搜索树的删除🧐
首先查找元素是否存在,不存在就直接返回,存在则要分四种情况分析:
- 要删除的节点没有孩子节点
- 要删除的节点只有左孩子节点
- 要删除的节点只有右孩子节点
- 要删除的节点有左右孩子节点
而第一种情况可以和第二种和第三种合并起来,所以真正情况有三种:
- 删除该节点且使被删除的节点的双亲节点指向被删除节点的左孩子节点——直接删除
- 删除该节点且使被删除的节点的双亲节点指向被删除节点的右孩子节点——直接删除
- 在它的右子树中寻找中序下的第一个节点(最小值),用它的值填补到被删除节点中(交换),再处理该节点的删除——替换法删除
参考代码
bool Erase(const K& key) {Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else //找到了,可以开始删除了{if (cur->_left == nullptr) //左为空{if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr) //右为空{if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else //左右都不为空{//右树的最小结点(最左结点)Node* subLeft = cur->_right;Node* parent = cur; //parent直接等于cur,防止删除根时parent为空导致交换出错while (subLeft->_left){parent = subLeft;subLeft = subLeft->_left;}swap(cur->_key, subLeft->_key); //找到了就交换if (subLeft == parent->_left) //看节点在左边还是右边{parent->_left = subLeft->_right;}else{parent->_right = subLeft->_right;}}return true;}}return false; }
全部代码🧐
namespace key {template<class K>struct BSTreeNode{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K& key):_left(nullptr), _right(nullptr), _key(key){}};template<class K>class BSTree{typedef BSTreeNode<K> Node;public:BSTree() = default; //c++11强制生成默认构造bool Insert(const K& key){if (_root == nullptr){_root = new Node(key);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else //默认情况下,不允许给重复值{return false;}}cur = new Node(key);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}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{return true;}}return false;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else //找到了,可以开始删除了{if (cur->_left == nullptr) //左为空{if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr) //右为空{if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else //左右都不为空{//右树的最小结点(最左结点)Node* subLeft = cur->_right;Node* parent = cur; //parent直接等于cur,防止删除根时parent为空导致交换出错while (subLeft->_left){parent = subLeft;subLeft = subLeft->_left;}swap(cur->_key, subLeft->_key);if (subLeft == parent->_left){parent->_left = subLeft->_right;}else{parent->_right = subLeft->_right;}}return true;}}return false;}~BSTree(){cout << "~destory" << endl;Destory(_root);}BSTree(const BSTree<K>& t){_root = Copy(t._root);}BSTree<K>& operator=(BSTree<K> t){swap(_root, t._root);return *this;}private:Node* Copy(Node* root){if (root == nullptr)return nullptr;Node* NewRoot = new Node(root->_key);NewRoot->_left = Copy(root->_left);NewRoot->_right = Copy(root->_right);return NewRoot;}void Destory(Node*& root){if (root == nullptr)return;Destory(root->_left);Destory(root->_right);delete root;root = nullptr;}Node* _root = nullptr;}; }
二叉搜索树的应用——K模型、KV模型🧐
K模型:K模型即只有Key作为关键码,结构中只需要存储Key即可。比如给一个名字判断他在不在名单中。在上面介绍的二叉搜索树就是K模型。
KV模型:让每一个Key都有一个对应的Value,即**<Key,Value>**的键值对。比如词典的中英对应,输入英文可以直接查找到对应的中文意思,再比如统计次数,可以快速找到一个单词出现的次数。
KV模型只需要在K模型上进行修改即可。
namespace kv {template<class K, class V>struct BSTreeNode{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _value;BSTreeNode(const K& key, const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){}};template<class K, class V>class BSTree{typedef BSTreeNode<K, V> Node;public:BSTree() = default; //c++11强制生成默认构造bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node(key,value);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){parent = cur;if (cur->_key < key){cur = cur->_right;}else if (cur->_key > key){cur = cur->_left;}else //默认情况下,不允许给重复值{return false;}}cur = new Node(key, value);if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}Node* 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{return cur;}}return nullptr;}bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else //找到了,可以开始删除了{if (cur->_left == nullptr) //左为空{if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}}else if (cur->_right == nullptr) //右为空{if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}}else //左右都不为空{//右树的最小结点(最左结点)Node* subLeft = cur->_right;Node* parent = cur; //parent直接等于cur,防止删除根时parent为空导致交换出错while (subLeft->_left){parent = subLeft;subLeft = subLeft->_left;}swap(cur->_key, subLeft->_key);if (subLeft == parent->_left){parent->_left = subLeft->_right;}else{parent->_right = subLeft->_right;}}return true;}}return false;}private:void Destory(Node*& root){if (root == nullptr)return;Destory(root->_left);Destory(root->_right);delete root;root = nullptr;}Node* _root = nullptr;}; }
二叉搜索树的性能分析🧐
二叉搜索树插入与删除都需要先进行查找,最优情况下,二叉搜索树为完全二叉树,时间复杂度为O(logN)。最坏情况下,二叉搜索树为单支树,时间复杂度为O(N)。当为单支树时,二叉搜索树的性能优势就没有了,所以我们后续会学习AVL树和红黑树,对二叉搜索树进行优化。
结尾👍
以上便是二叉搜索树的全部内容,如果有疑问或者建议都可以私信笔者交流,大家互相学习,互相进步!🌹
相关文章:

【C++第十七章】二叉搜索树
【C第十七章】二叉搜索树 二叉搜索树的介绍🧐 二叉搜索树又称二叉排序树,它可能是空树,也可能是具有以下性质的二叉树: 若它的左子树不为空,则左子树上的所有节点的值小于根节点的值若它的右子树不为空,则…...

Springboot 文件上传
文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程。 文件上传前端需要完成的准备: 需要提交一个form表单,表单必须包含以下三点(上传文件页面三要素) …...

简单认识redis-5 jdbc 与 jedis 使用的区别
概念与功能定位 JDBC (Java Database Connectivity) JDBC 是 Java 语言用于连接数据库(如 MySQL、Oracle 等关系型数据库)的标准 API。它提供了一套统一的接口,让 Java 程序能够与各种数据库进行交互,执行 SQL 语句(如…...

Unity3d动画插件DoTween使用指南
1、DoTween是什么? DoTween是一款对象动画类插件,它是一款针对Unity 3D编辑器的、快速高效的、安全的、面向对象的补间动画引擎,并且对C#语言开发做出了很多的优化。另外,它使得开发者无需通过Unity内置的Animator或Coroutines即可…...

学习函数知识
学习函数是编程中的重要基础,以下是关于函数的详细知识点: 1. 函数的定义 函数是一组执行特定任务的代码块,可以重复使用。在 JavaScript 中,可以通过以下方式定义函数: 函数声明: function functionNam…...

案例-表白墙简单实现
文章目录 效果展示初始画面提交内容后画面(按键按下) 代码区 效果展示 初始画面 提交内容后画面(按键按下) 代码区 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">…...

和鲸科技创始人范向伟:拐点即将来临,AI产业当前的三个瓶颈
在科技迅猛发展的时代,人工智能(AI)无疑已经成为引领新一轮产业革命的核心动力之一。全球企业纷纷拥抱AI技术,试图借助其变革力量在竞争中突围,然而业界对AI产业化的拐点何时来临却众说纷纭。毕竟AI技术从实验室到商业…...

基于函数计算FC 部署 ComfyUI实现AI生图 的优势
基于函数计算FC 部署 ComfyUI实现AI生图 的优势 部署ComfyUI实现AI生图使用函数计算FC 一键部署ComfyUI 绘画平台的优势有哪些? 在文章开始之前,先来看一下基于函数计算FC 部署 ComfyUI实现AI生图 的大概步骤,整个基础部署操作比较简单。即便…...

瑞萨IDE:CS+ for CC编译过程中执行脚本文件
最近发现使用CS for CC IDE发现一个很有意思的功能。编译工程过程中,IDE自动执行Python脚本和批处理脚本,极大地提高开发效率。 编写好脚本文件后,在IDE中选择CC-RH(Build Tool)->Common Options->Others。 Co…...

在 CentOS 上安装 Docker 的步骤
在 CentOS 上安装 Docker 的步骤如下: 步骤 1:更新系统包 sudo yum update -y步骤 2:安装依赖包 确保安装了 yum-utils、device-mapper-persistent-data 和 lvm2,这些是 Docker 运行所需的依赖项: sudo yum instal…...

【C#生态园】探索地理信息系统软件套件与库:功能、API和应用
探索地理信息系统:软件套件与库详解 前言 地理信息系统(GIS)是当今世界上广泛使用的技术之一,它以空间数据为基础,能够提供丰富的地理信息分析和可视化功能。在GIS领域,有许多优秀的软件套件和库…...

Jupyter的使用分享
文章目录 碎碎念安装方法1.安装Anaconda方法2.通过库的安装方式 启动使用教程1.指定目录打开2.启动后的简单使用 小结 碎碎念 前情提示 之前与许多小伙伴交流的时候,发现大家对于pycharm更容易上手(可能是比较好设置中文的原因),在…...

24龙信比赛复现
案情简介: 近期,某公安机关接到受害人报案:通过微信添加认识一位相亲中介客服,客服邀约其与“相亲”对象进行选妃,受害人上钩后,整个过程被涉案团伙录音录像,同时,该客服以有更多的…...

PHP反射机制
HP反射机制是PHP语言中的一个强大特性,它允许程序在运行时检查、获取和操作类、方法、属性等元素的信息。这一机制极大地提高了PHP代码的灵活性和可维护性,使得开发者能够在不修改原有代码结构的情况下,动态地了解并操作代码。以下是对PHP反射…...

使用阿里云试用资源快速部署web应用-dofaker为例
本文介绍使用阿里云的试用资源部署dofaker的方法,本教程主要作学习在阿里云部署web应用之用,部署好应用之后,可以在任何地点通过公网ip访问web应用。 一、创建云主机 登录阿里云账户之后,点击控制台: 点击云服务器EC…...

需求11——解决字段无法清空的两个小bug
目录 背景 第一个小bug——问题阐述 第一个小bug——解决方案 第二个小bug——问题阐述 第二个小bug——解决方案 总结 背景 已经写了一个上午的文章了,写完这篇就可以去吃饭了。这也是这几个月的我写的最后一个小bug文章,把这篇文章写完就搞定了…...

mysql学习教程,从入门到精通,SQL 创建索引(CREATE INDEX 语句)(35)
1、SQL 创建索引(CREATE INDEX 语句) 在SQL中,创建索引(CREATE INDEX)是一种用于提高数据库查询性能的方法。索引类似于书的目录,通过它可以更快地定位到表中的特定行。以下是一个创建索引的示例,以及对其各部分的解释…...

Pikachu-Cross-Site Scripting-DOM型xss_x
查看代码,输入的内容,通过get请求方式,用text 参数带过去; 获取text内容,赋值给xss 然后拼接到 dom 里;构造payload的关键语句: <a href"xss">就让往事都随风,都随风吧</a&…...

Pikachu-Cross-Site Scripting-xss之htmlspecialchars
首先输入各种字符 查看页面元素,可以看到这里对一些符号做了转换,但是 单引号等几个符号没处理; 从代码上看;使用单引号做闭合; 构造payload a onclickalert(11) 提交,得到xss攻击...

CSS基础中padding详解
文章目录 CSS基础中padding详解一、引言二、Padding基础1、Padding属性1.1、Padding的四个方向 2、Padding的值类型3、代码示例 三、Padding简写方法1、简写顺序2、简写规则3、代码示例 四、Padding对元素大小的影响1、解决方案1.1、Box-sizing属性1.2、计算实际宽度 五、总结 …...

OpenGL笔记十九之相机系统
OpenGL笔记十九之相机系统 —— 2024-10-02 晚上 bilibili赵新政老师的教程看后笔记 code review! 文章目录 OpenGL笔记十九之相机系统1.运行1.1.游戏相机1.2.轨迹球相机 2.游戏相机与轨迹球相机切换3.博主笔记本要运行需要更改的文件更改1:28_OpenGL_CameraSystem/applicat…...

P-Tuning v2:一种普遍有效的提示调整方法
人工智能咨询培训老师叶梓 转载标明出处 预训练语言模型通过微调(fine-tuning)来适应特定任务虽然效果显著,但存在训练成本高、参数存储量大等问题。为了解决这些问题,清华大学的研究者们提出了一种名为P-Tuning v2的提示调整&am…...

微信小程序启动不起来,报错凡是以~/包名/*.js路径的文件,都找不到,试过网上一切方法,最终居然这么解决的,【避坑】命运的齿轮开始转动
app.json "resolveAlias": {"~/*": "/*"},文件代码也没有问题,网上的方法试过来了,大模型AI也问过遍,熬夜到凌晨2点半,最不可思议的是居然是因为微信开发者工具版本的问题,我真的是笑死…...

C#串口温度读取
背景:每天学点,坚持 要安装好虚拟串口和modbus poll,方便调试(相关资源在文末,也可以私信找我要) 传感器部分使用的是达林科技的DL11B-MC-D1,当时42软妹币买的(官网上面有这个传感…...

2.5 Spring Boot整合Spring MVC框架
今天,我将向大家介绍如何在Spring Boot中整合Spring MVC框架,并展示如何创建和测试控制层(Controller)。 首先,让我们简要回顾一下Spring MVC。Spring MVC是一个基于Servlet的MVC框架,它简单、侵入性小&am…...

Java 归并排序
归并排序(Merge Sort)是一种基于分治法的排序算法。它将一个大数组分成两个较小的子数组,分别对每个子数组进行排序,然后再将这两个已排序的子数组合并成一个完整的已排序数组。归并排序的时间复杂度为 O(n log n),其中…...

20241008深度学习动手篇
文章目录 1.如何写一个神经网络进行训练?1.1创建一个子类,搭建你需要的神经网络结构1.2 加载数据集1.3 自定义一些指标评估函数1.4训练1.5 结果展示 2.参考文献 1.如何写一个神经网络进行训练? 1.1创建一个子类,搭建你需要的神经网络结构 # File: 241008LeNet.py # Author:…...

对序列化反序列化在项目中的使用优化
文章目录 序列化是什么?常见的序列化协议使用序列化反序列化序列化List反序列化List 查看源码,分析不足进行改善 序列化是什么? 如果我们需要持久化 Java 对象比如将 Java 对象保存在文件中,或者在网络传输 Java 对象,…...

查看 git log的过程中看到 :说明日志输出可能超出屏幕大小,系统进入了分页模式
在命令行提示符中,通常 : 表示系统等待进一步的输入。如果你在查看 git log 的过程中看到 :,说明日志输出可能超出屏幕大小,系统进入了分页模式,默认使用 less 命令查看内容。 此时你可以: 按 q 退出日志查看。按 En…...

Linux--信号量详解
目录 一、信号量 1、信号量相关函数 2、多线程环形队列生产消费模型 3、实现代码 信号量是将整体的资源分割成多份使用 信号量本质是对资源的预定机制 一、信号量 1、信号量相关函数 创建信号量: sem_init: int sem_init(sem_t *sem, int pshared, unsigned int value); …...