C++——二叉树

引入

 map和set特性需要先铺垫二叉搜索树,而二叉搜索树也是一种树形结构
 二叉搜索树的特性了解,有助于更好的理解map和set的特性

1.二叉搜索树的概念及优缺点

1.1二叉搜索树的概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树

左子树的值<根的值<右子树的值

int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};

搜索二叉树通过二分查找可以轻松找到目标值,避免了暴力遍历的方式。

根据搜索二叉树的性质,目标值会出现在左子树,右子树则是比目标值大的值。因此,搜索二叉树查找一个值的最坏情况只需要查找树的高度次 

既然提到了最坏情况,那么搜索二叉树的时间复杂度是多少呢?

搜索二叉树的增删查改的时间复杂度实际上是O(N),因为这棵树有可能会蜕化成一个 "单边树"(也就是只往一边存,另外一边没有节点)。

 1.2二叉搜索树的部分使用及其实现

 二叉搜索树的查找

从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
最多查找高度次,走到到空,还没找到,这个值不存在。
//查找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;}}//while循环走到头(遇到空节点)那就说明没找到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){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}//走到这说明可以插入了cur = new Node(key);//看情况把它接到父节点的左边还是右边if (parent->_key < key){parent->_right = cur;}else{parent->_left = cur;}return true;}

 

二叉搜索树的删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回,
否则要删除的结点可能分下面四种情 况:

要删除的结点无孩子结点

要删除的结点只有左孩子结点

要删除的结点只有右孩子结点

要删除的结点有左、右孩子结点

看起来有待删除节点有4中情况,实际情况无孩子可以与情况只有左或者只有右合并起来
因此真正的删除过程如下:
无孩子节点也就是叶子节点
删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除
删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除
替换法删除:找一个能替换我的节点,交换值转换删除他
右两种替换方法:1.左子树的最大(最右)节点 2.右子树的最小(最左)节点

 

如果原本4节点还有还记记得托付给其父节点 (由于替换法删除是取左子树的最右(右子树的最左)节点,所以哪怕4节点还有子节点,那也只能有一个),比如:

 

	//删除bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;//先找到要删的那个值while (cur){if (cur->_key < key){//cur走parent也要走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->_right){//cur左孩子节点为空,若cur在其父节点的右边,那么其右孩子一定大于cur的父节点//右边托付parent->_right = cur->_right;}else{//左边托付parent->_left = cur->_right;}}//托付完删除delete cur;return true;}//要删除的节点的右孩子节点为空else if(cur->_right == nullptr){if (cur == _root){//要删的值在根节点,那直接把根节点给左节点就行了_root = cur->_left;}else{if (cur == parent->_right){//若cur在其父节点的右边,那么其左孩子一定大于于cur的父节点parent->_right = cur->_left;}else{//左边托付parent->_left = cur->_left;}}//托付完删除delete cur;return true;}else{//cur左右都非空Node* rightMin = cur->_right;//右边最小节点Node* rightMinParent = cur;//右边最小节点的父节点//找右边的最小节点while (rightMin->_left){rightMinParent = rightMin;rightMin = rightMin->_left;}//找到就替换一下cur->_key = rightMin->_key;//最小节点的孩子得判断是rightMin父亲的哪一边接收if (rightMin == rightMinParent->_left){rightMinParent->_left = rightMin->_right;}else{rightMinParent->_right = rightMin->_right;}delete rightMin;return true;}}}//找不到return false;}

 2.二叉搜索树的实现

2.1上述补充

节点

template<class K>
struct BSTreeNode
{typedef BSTreeNode<K> Node;Node* _left;Node* _right;K _key;BSTreeNode(const K& key):_left(nullptr),_right(nullptr),_key(key){}
};

二叉树的 


template<class K>
struct BSTree
{typedef BSTreeNode<K> Node;
public://强制生成默认构造BSTree() = default;BSTree(const BSTree<K>& t){_root = Copy(t._root);}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);}BSTree<K>& operator=(BSTree<K> t){swap(_root, t._root);return *this;}~BSTree(){Destroy(_root);}void Destroy(Node* root)//后序遍历析构(销毁){if (root == nullptr){return;}Destroy(root->_left);Destroy(root->_right);delete root;}private:Node* _root = nullptr;
};

2.2查找、插入、删除递归实现

查找递归

因为无法传递根节点,所以要封装一层。

bool FindR(const K& key){return _FindR(_root, key);}bool _FindR(Node* root, const K& key){if (root == nullptr)return false;if (root->_key < key){return _FindR(root->_right, key);}else if (root->_key > key){return _FindR(root->_left, key);}else{return true;

插入递归

注意:插入的值如何与父节点连接

可以在传(递归)的根节点上加引用,这样每深入一层,那么这层的root就是上一场root->left(right)的引用,也就是说最后一层他会自动连接新节点

	bool InsertR(const K& key){return _InsertR(_root, key);}bool _InsertR(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key < key){return _InsertR(root->_right, key);}else if (root->_key > key){return _InsertR(root->_left, key);}else{return false;}}

删除递归

这里的引用和上面一样

	bool EraseR(const K& key){return _EraseR(_root, key);}bool _EraseR(Node*& root, const K& key){if (root == nullptr)return false;if (root->_key < key){return _EraseR(root->_right, key);}else if (root->_key > key){return _EraseR(root->_left, key);}else{Node* del = root;if (root->_right == nullptr){root = root->_left;}else if (root->_left == nullptr){root = root->_right;}else{Node* rightMin = root->_right;while (rightMin->_left){rightMin = rightMin->_left;}swap(root->_key, rightMin->_key);return _EraseR(root->_right, key);}delete del;return true;}}

3. 搜索二叉树的应用

3.1K模型

K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到
的值
比如:给一个单词word,判断该单词是否拼写正确
具体方式如下:
以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

3.2kv模型

KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方
式在现实生活中非常常见:
比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英
文单词与其对应的中文<word, chinese>就构成一种键值对;
再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出
现次数就是<word, count>就构成一种键值对

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

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

相关文章

Python中使用opencv-python进行人脸检测

Python中使用opencv-python进行人脸检测 之前写过一篇VC中使用OpenCV进行人脸检测的博客。以数字图像处理中经常使用的lena图像为例&#xff0c;如下图所示&#xff1a; 使用OpenCV进行人脸检测十分简单&#xff0c;OpenCV官网给了一个Python人脸检测的示例程序&#xff0c;…

Backtrader 文档学习- Plotting - Plotting Date Ranges

Backtrader 文档学习- Plotting - Plotting Date Ranges 1.概述 1.9.31.x版本增加了绘制部分图形的功能。 可以使用策略实例中保留完整长度的时间戳数组的索引或者使用实际的datetime.date 或datetime.datetime 实例来限制需要绘制的内容。 仍然可以使用标准的cerebro.plot…

静态时序分析:建立时间分析

静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 在静态时序分析中&#xff0c;建立时间检查约束了触发器时钟引脚&#xff08;时钟路径&#xff09;和输入数据引脚&#xff08;数据路径&#xff09;之间的时序关系&#x…

android中实现设备尺寸适配

1、引言 设备尺寸适配的重要性想必就不用我多说了&#xff0c;在我发布的历史文章中我曾谈过Qt中的设备尺寸适配问题&#xff0c;那这里我就来教大家如何在android中做设备尺寸适配。在android中设备尺寸适配的方式有好几种&#xff0c;但我喜欢的还是使用获取设备真实尺寸然后…

c语言游戏实战(4):人生重开模拟器

前言&#xff1a; 人生重开模拟器是前段时间非常火的一个小游戏&#xff0c;接下来我们将一起学习使用c语言写一个简易版的人生重开模拟器。 网页版游戏&#xff1a; 人生重开模拟器 (ytecn.com) 1.实现一个简化版的人生重开模拟器 &#xff08;1&#xff09; 游戏开始的时…

PLC在物联网中位置—承上启下,与上位机下位机的关联。

谈到物联网&#xff0c;就绕不开PLC&#xff0c;本文着重介绍PLC的定义、与单片机的区分&#xff0c;价值、物联网中的位置&#xff0c;以及和上位机、下位机的关联&#xff0c;让友友们对PLC有个全面的认知。 一、什么是PLC PLC是可编程逻辑控制器&#xff08;Programmable L…

UI自动刷新大法:DataBinding数据绑定

之前我们讲了DataBinding在Activity、Fragment、RecyclerView中的基础使用&#xff0c;而那些常规使用方法里&#xff0c;每当绑定的变量发生数据变化时&#xff0c;都需要ViewDataBinding重新设值才会刷新对应UI。而DataBinding通过内部实现的观察者模式来进行自动刷新UI&…

go消息队列RabbitMQ - 订阅模式-direct

1.发布订阅 在Fanout模式中&#xff0c;一条消息&#xff0c;会被所有订阅的队列都消费。但是&#xff0c;在某些场景下&#xff0c;我们希望不同的消息被不同的队列消费。这时就要用到Direct类型的Exchange。 在Direct模型下&#xff1a; 队列与交换机的绑定&#xff0c;不能…

第 384 场 LeetCode 周赛题解

A 修改矩阵 模拟 class Solution { public:vector<vector<int>> modifiedMatrix(vector<vector<int>> &matrix) {int m matrix.size(), n matrix[0].size();vector<int> mx(n, INT32_MIN);for (int i 0; i < m; i)for (int j 0; j &l…

Java微服务学习Day1

文章目录 认识微服务服务拆分及远程调用服务拆分服务远程调用提供者与消费者 Eureka注册中心介绍构建EurekaServer注册user-serviceorder-service完成服务拉取 Ribbon负载均衡介绍原理策略饥饿加载 Nacos注册中心介绍配置分级存储负载均衡环境隔离nacos注册中心原理 认识微服务…

Python : 使用python实现学生管理系统的功能,详细注释

一、学生管理系统 学生描述&#xff1a;姓名、年龄、成绩 学生管理系统功能&#xff1a;添加学生信息、删除学生信息、根据姓名修改学生信息、根据姓名查询学生信息、显示所有学生信息、退出系统 二、代码说明 1. 将每一个学生的信息放一个元组中&#xff0c;再把元组添加到列表…

单片机基础入门:简单介绍51单片机的工作原理

在电子技术领域&#xff0c;单片机是实现智能化控制不可或缺的关键元件。它们集成了许多功能于一身&#xff0c;成为了各种电子系统的心脏。为了更好地理解单片机如何工作&#xff0c;本文将重点介绍51单片机的基本组成和工作原理。 51单片机是一种广泛使用的微控制器&#xf…

【UE 求职】学了虚幻引擎可以应聘哪些岗位?

目录 1 领域1.1 游戏开发领域1.2 影视和动画制作1.3 建筑和工程可视化1.4 模拟和训练1.5 其他领域 2 如何做好一份简历1. 明确简历目标2. 突出UE5相关技能3. 展示相关项目经验4. 教育背景5. 专业经验6. 软技能7. 证书和奖项8. 定制化和校对 &#x1f64b;‍♂️ 作者&#xff1…

使用PHPStudy搭建本地web网站并实现任意浏览器公网访问

文章目录 [toc]使用工具1. 本地搭建web网站1.1 下载phpstudy后解压并安装1.2 打开默认站点&#xff0c;测试1.3 下载静态演示站点1.4 打开站点根目录1.5 复制演示站点到站网根目录1.6 在浏览器中&#xff0c;查看演示效果。 2. 将本地web网站发布到公网2.1 安装cpolar内网穿透2…

springcloud分布式架构网上商城源码和论文

首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。本项…

Unity Meta Quest MR 开发(四):使用 Scene API 和 Depth API 实现深度识别和环境遮挡

文章目录 &#x1f4d5;教程说明&#x1f4d5;Scene API 实现遮挡&#x1f4d5;Scene API 实现遮挡的缺点&#x1f4d5;Depth API 实现遮挡⭐导入 Depth API⭐修改环境配置⭐添加 EnvironmentDepthOcclusion 预制体⭐给物体替换遮挡 Shader⭐取消现实手部的遮挡效果 此教程相关…

Peter算法小课堂—背包问题

我们已经学过好久好久的动态规划了&#xff0c;动态规划_Peter Pan was right的博客-CSDN博客 那么&#xff0c;我用一张图片来概括一下背包问题。 大家有可能比较疑惑&#xff0c;优化决策怎么优化呢&#xff1f;答案是&#xff0c;滚动数组&#xff0c;一个神秘而简单的东西…

点云标注工具

目录 3d手势识别 c 3d关键点&#xff0c;Bounding Box Labels Rectangle Labels KITTI 3D Ground Truth Annotator c标注工具 3d手势识别 GitHub - 99xtaewoo/Automated-Hand-3D-pose-annotation-Tool: Automated Hand 3D pose annotation Tool c 3d关键点&#xff0c;Bou…

bcdedit /store 填什么,Windows11的BCD文件在哪里?

Windows11为EFI引导&#xff0c;bcd文件在 EFI分区的 \EFI\Microsoft\Boot\BCD 可以选择挂载EFI分区&#xff0c;或者使用如下方式&#xff0c;该路径可充当盘符使用。 例 bcdedit /store Z:\EFI\Microsoft\Boot\BCD /enum /v

【LeetCode每日一题】二维前缀和基本概念与案例

二维前缀和 根据某个块块 的 左上角坐标&#xff0c;和右下角坐标 求出 块块的累加和。 304. 二维区域和检索 - 矩阵不可变 /*** param {number[][]} matrix*/ var NumMatrix function(matrix) {let row matrix.length;let col matrix[0].length;// 初始化一个二维数组&am…