【C++】二叉搜索树(手撕插入、删除、寻找)

一、什么是二叉搜索树

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

二、二叉搜索树的操作

2.1二叉搜索树的寻找

a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。

b、最多查找高度次,走到到空,还没找到,这个值不存在。

bool Find(const K& key)
{Node* cur = _root;while (cur){if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return true;}return false;}
}
2.2二叉搜索树的插入

插入的具体过程如下:

a. 树为空,则直接新增节点,赋值给root指针

b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

bool Insert(const K& key)
{if (_root == nullptr){_root = new Node(key);return true;}Node* curparent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){curparent = cur;cur = cur->_right;}else if (key < cur->_key){curparent = cur;cur = cur->_left;}else{//找到相同元素就报错return false;}}cur = new Node(key);if (cur->_key > curparent->_key){curparent->_right = cur;}else{curparent->_left = cur;}return true;
}
2.3二叉搜索树的删除

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

  • 情况1:要删除的结点无孩子结点。

让父亲节点指向孩子节点的左节点或右节点即可(指向nullptr),该种情况可以在情况2和情况3处理

        

  • 情况2:要删除的结点只有左孩子结点。

如果删除节点是左孩子,那就让父亲节点的左指针指向删除节点的左节点,如果删除节点右孩子,那就让父亲节点的右指针指向删除节点的左节点(还要注意父亲节点不存在,及删除的是根节点的情况)

  • 情况3:要删除的结点只有右孩子结点。

如果删除节点是左孩子,那就让父亲节点的左指针指向删除节点的右节点,如果删除节点右孩子,那就让父亲节点的右指针指向删除节点的右节点

  • 况4:要删除的结点有左、右孩子结点。

找左子树的最大节点或者右子树的最小节点与删除节点的值互换(只有这两个节点满足二叉搜索树的性质),然后删除。以找右子树最小节点举例,交换值以后,让最小节点的父亲节点的左指针指向最小节点的右节点,因为右子树最小节点是最左边的节点,但他可能存在右孩子。

要注意特殊情况,右子树最小节点就是删除节点的右孩子,此时就要让父亲节点的右指针指向删除节点的右孩子

bool Erase(const K& key)
{Node* curparent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){curparent = cur;cur = cur->_right;}else if (key < cur->_key){curparent = cur;cur = cur->_left;}else{//删除操作//如果删除节点左子树为空if (cur->_left == nullptr){if (_root == cur){_root = _root->_right;}else{if (curparent->_left == cur){curparent->_left = cur->_right;}else{curparent->_right = cur->_right;}}delete cur;}//如果删除节点右子树为空else if (cur->_right == nullptr){if (_root == cur){_root = _root->_left;}else{if (curparent->_left == cur){curparent->_left = cur->_left;}else{curparent->_right = cur->_left;}}delete cur;}else{//删除节点左右都不为空Node* RightMinParent = cur;Node* RightMin = cur->_right;while (RightMin->_left){RightMinParent = RightMin;RightMin = RightMin->_left;}swap(RightMin->_key, cur->_key);if (RightMinParent->_left == RightMin){RightMinParent->_left = RightMin->_right;}else{RightMinParent->_right = RightMin->_right;}delete RightMin;}return true;}}return false;
}

三、二叉搜索树的应用

K模型K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。

       比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

  • 以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
  • 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

KV模型每一个关键码key,都有与之对应的值Value,即的键值对。该种方式在现实生活中非常常见:

  • 比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文就构成一种键值对;
  • 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是就构成一种键值对。

ps、KV模型的二叉搜索树与K模型的二叉搜索树相类似,因为KV模型的删除、寻找等操作是依靠key的与value值无关

namespace key_value
{template<class K,class V>struct BSTreeNode{BSTreeNode(const K& key,const V& value):_left(nullptr), _right(nullptr), _key(key),_value(value){}struct BSTreeNode* _left;struct BSTreeNode* _right;K _key;V _value;};template<class K,class V>class BSTree{typedef struct BSTreeNode<K,V> Node;private://销毁二叉搜索树void Destory(Node* root){//后续递归删除if (root == nullptr){return;}Destory(root->_left);Destory(root->_right);delete root;}public:~BSTree(){Destory(_root);_root = nullptr;}bool Insert(const K& key,const V& value){if (_root == nullptr){_root = new Node(key, value);return true;}Node* curparent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){curparent = cur;cur = cur->_right;}else if (key < cur->_key){curparent = cur;cur = cur->_left;}else{//找到相同元素就报错return false;}}cur = new Node(key,value);if (cur->_key > curparent->_key){curparent->_right = cur;}else{curparent->_left = cur;}return true;}void _Inorder(Node* ret){if (ret == nullptr)return;_Inorder(ret->_left);cout << ret->_key << ":"<<ret->_value<<endl;_Inorder(ret->_right);}void Inorder(){_Inorder(_root);cout << endl;}bool Find(const K& key){Node* cur = _root;while (cur){if (key > cur->_key){cur = cur->_right;}else if (key < cur->_key){cur = cur->_left;}else{return true;}return false;}}bool Erase(const K& key){Node* curparent = nullptr;Node* cur = _root;while (cur){if (key > cur->_key){curparent = cur;cur = cur->_right;}else if (key < cur->_key){curparent = cur;cur = cur->_left;}else{//删除操作//如果删除节点左子树为空if (cur->_left == nullptr){if (_root == cur){_root = _root->_right;}else{if (curparent->_left == cur){curparent->_left = cur->_right;}else{curparent->_right = cur->_right;}}delete cur;}//如果删除节点右子树为空else if (cur->_right == nullptr){if (_root == cur){_root = _root->_left;}else{if (curparent->_left == cur){curparent->_left = cur->_left;}else{curparent->_right = cur->_left;}}delete cur;}else{//删除节点左右都不为空Node* RightMinParent = cur;Node* RightMin = cur->_right;while (RightMin->_left){RightMinParent = RightMin;RightMin = RightMin->_left;}swap(RightMin->_key, cur->_key);if (RightMinParent->_left == RightMin){RightMinParent->_left = RightMin->_right;}else{RightMinParent->_right = RightMin->_right;}delete RightMin;}return true;}}return false;}private:Node* _root = nullptr;};void test(){BSTree<string,string> t;t.Insert("apple", "苹果");t.Insert("pear", "梨");t.Insert("pen", "笔");t.Insert("insert", "插入");t.Erase("apple");t.Erase("pen");t.Inorder();t.~BSTree();}
}

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

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

相关文章

OSError: [WinError 1455] 页面文件太小,无法完成操作 的问题

实质问题是报错&#xff1a;caffe2_detectron_ops.dll“ or one of its dependencies 还需要安装一个包&#xff1a; pip install intel-openmp 安装之后顺利测试通过。

Tomcat7+ 弱口令 后台getshell漏洞

1 漏洞背景 Tomcat 是一个流行的开源Web应用服务器&#xff0c;用于部署和运行Java Web应用程序。Tomcat 7 版本中存在一个安全隐患&#xff0c;即默认的管理员密码可能较弱或者未被修改&#xff0c;攻击者可以利用这一漏洞登录到Tomcat的管理后台&#xff0c;并上传恶意的WAR…

LeetCode100题总结

LeetCode100题总结 前言LeetCode100题总结题型梳理双指针11. 盛最多水的容器234.回文链表75.颜色分类206.反转链表142.环形链表215.三数之和 滑动窗口3. 无重复字符的最长子串209. 长度最小的子数组438. 找到字符串中所有字母异位词 广搜102. 二叉树的层序遍历200. 岛屿数量617…

轮转数组 与 消失的数字

轮转数组 思路一 创建一个新内存空间&#xff0c;将需轮转的数依次放入&#xff0c;之后在把其它数放入 代码&#xff1a; void rotate(int* nums, int numsSize, int k) {k k % numsSize;// 确定有效的旋转次数if(k 0)return;int* newnums (int*)malloc(sizeof(int) * nu…

2024数据分析管理、数字经济与教育国际学术会议(ICDAMDEE2024)

2024数据分析管理、数字经济与教育国际学术会议(ICDAMDEE2024) 会议简介 2024年数据分析管理、数字经济和教育国际学术会议&#xff08;ICDAMDEE 2024&#xff09;将在武汉举行。会议不仅展示了来自世界各地的研究专家围绕数据分析管理、数字经济和教育的最新科研成果&#xf…

纯血鸿蒙APP实战开发——Grid和List内拖拽交换子组件位置

Grid和List内拖拽交换子组件位置 介绍 本示例分别通过onItemDrop()和onDrop()回调&#xff0c;实现子组件在Grid和List中的子组件位置交换。 效果图预览 使用说明&#xff1a; 拖拽Grid中子组件&#xff0c;到目标Grid子组件位置&#xff0c;进行两者位置互换。拖拽List中子…

【项目实战】使用Yolov8 + tesseract 实现身份证信息解析(OCR) + 输入可为图片或者pdf + 完整代码 + 整体方案 + 全网首发

本项目可用于实验,毕业设计参考等。整体效果如下所示: 说明:图片来源于网络,如有侵权,请联系作者删除。 目录 一 数据集制作

Omnity 进展月报 | 2024.4.1-4.30

Omnity 大事摘要 1、Octopus 官宣升级为 Omnity。 2、Omnity 4月28号正式上线&#xff0c;实现BTC 和 ICP 之间跨链转账 Runes 资产。 3、为庆祝上线&#xff0c;以符文 HOPE•YOU•GET•RICH 为资产&#xff0c;发红包快速触达大量用户&#xff0c;体验跨链服务。 4、Omni…

你知道C++多少——默认成员函数

&#x1f308;个人主页&#xff1a;小新_- &#x1f388;个人座右铭&#xff1a;“成功者不是从不失败的人&#xff0c;而是从不放弃的人&#xff01;”&#x1f388; &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd; &#x1f3c6;所属专栏&#xff1…

Vulstack红队评估(一)

文章目录 一、环境搭建1、网络拓扑2、web服务器(win7)配置3、域控&#xff08;winserver2008&#xff09;配置4、域内机器&#xff08;windows 2003&#xff09;配置5、调试网络是否通常 二、web渗透1、信息搜集2、端口扫描3、目录扫描4、弱口令5、phpmyadmin getshell日志gets…

Android 开机启动扫描SD卡apk流程源码分析

在开机的时候&#xff0c;装在SD卡的apk和装在系统盘的apk扫描过程不一样&#xff0c;系统盘apk在系统启动过程中扫描&#xff0c;而SD卡上的就不是&#xff0c;等系统启动好了才挂载、扫描&#xff0c;下面就说下SD扫描的流程&#xff1a; 在SystemServer启动MountService&am…

ARM架构安全特性之防御执行技术

安全之安全(security)博客目录导读 目录 1、侧信道攻击威胁 2、推测屏障Speculation Barriers 3、栈溢出攻击威胁 4、指针认证PAC 5、分支目标识别BTI 6、内存安全违规威胁 7、内存标记扩展MTE 8、加强数据保护 9、特权不可访问&#xff08;Privileged Access Never …

[图解]SysML和EA建模住宅安全系统-01

1 00:00:00,980 --> 00:00:03,100 接下来&#xff0c;我们来看一下案例 2 00:00:04,930 --> 00:00:06,750 我们这次课程的案例 3 00:00:07,090 --> 00:00:13,800 选用了SysML实用指南的书上 4 00:00:13,810 --> 00:00:16,180 第十七章这个案例 5 00:00:16,350 …

sqlite3命令行工具无法退出问题处理

一、背景&#xff1a; 软件使用的后台数据库为sqlite&#xff0c;linux主机系统层面使用sqlite3命令行工具登录数据库后&#xff0c;无法执行sql脚本&#xff0c;无法退出sqlite3。无法执行ctrlc&#xff0c;执行ctrlz后sqlite3前台进程被中断&#xff0c;但是该进程没有退出。…

每日OJ题_贪心算法四⑤_力扣354. 俄罗斯套娃信封问题

目录 力扣354. 俄罗斯套娃信封问题 解析代码1_动态规划&#xff08;超时&#xff09; 解析代码2_重写排序贪心二分 力扣354. 俄罗斯套娃信封问题 354. 俄罗斯套娃信封问题 难度 困难 给你一个二维整数数组 envelopes &#xff0c;其中 envelopes[i] [wi, hi] &#xff0…

数据分析——业务指标分析

业务指标分析 前言一、业务指标分析的定义二、业务问题构建问题构建的要求 三、业务问题的识别在识别问题的阶段对于企业内部收益者的补充 四、竞争者分析竞争者分析的内容竞争者分析目的案例 五、市场机会识别好的市场机会必须满足的条件市场机会案例 六、风险控制数据分析师常…

2024数维杯数学建模B题生物质和煤共热解问题的研究原创论文分享

大家好&#xff0c;从昨天肝到现在&#xff0c;终于完成了2024数维杯数学建模挑战赛B题的完整论文啦。 实在精力有限&#xff0c;具体的讲解大家可以去讲解视频&#xff1a; 2024数维杯数学建模B题煤共热解每一问高质量完整代码讲解&#xff01;_哔哩哔哩_bilibili 2024数维杯…

Docker 直接运行一个 Alpine 镜像

由于镜像很小&#xff0c;下载时间往往很短&#xff0c;读者可以直接使用 docker run 指令直接运行一个 Alpine 容器&#xff0c;并指定运行的 Linux 指令&#xff0c;例如&#xff1a; PS C:\Users\yhu> docker run alpine echo 123 Unable to find image alpine:latest lo…

【机器学习300问】86、简述超参数优化的步骤?如何寻找最优的超参数组合?

本文想讲述清楚怎么样才能选出最优的超参数组合。关于什么是超参数&#xff1f;什么是超参数组合&#xff1f;本文不赘述&#xff0c;在之前我写的文章中有详细介绍哦&#xff01; 【机器学习300问】22、什么是超参数优化&#xff1f;常见超参数优化方法有哪些&#xff1f;htt…

ORA-609频繁出现在alert.log,如何解决?

ORA-609就alertlog中比较常见的一个报错&#xff0c;虽然并没有太大的影响&#xff0c;但是频繁的出现在alert log也是很让人厌烦的事情&#xff0c;本文介绍如何排查解决ORA-609问题。 1.ORA-609官方定义 could not attach to incoming connection Cause Oracle process cou…