【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.mzph.cn/web/8512.shtml

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

相关文章

[前端异步]循环中所有异步任务完成才往下运行?

reqData(){this.startLoading();//获取分析结果数据for (let i 1; i <24;i 1) {try {let formattedValue i.toString().padStart(4, 0);this.requestData(formattedValue).then((PromiseResult) > {if(PromiseResult.status"success"){this.images.push(Pro…

hadoop学习---基于Hive的聊天数据分析报表可视化案例

背景介绍&#xff1a; 聊天平台每天都会有大量的用户在线&#xff0c;会出现大量的聊天数据&#xff0c;通过对聊天数据的统计分析&#xff0c;可以更好的对用户构建精准的用户画像&#xff0c;为用户提供更好的服务以及实现高ROI的平台运营推广&#xff0c;给公司的发展决策提…

C++:AVL树

概念&#xff1a; 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查 找元素相当于在顺序表中搜索元素&#xff0c;效率低下。 如图所示&#xff0c;搜索二叉树不能面对右边的树&#xff0c;这种极端的情况&#xf…

JavaScript创建数组对象的两种方式

JavaScript创建数组对象的两种方式有以下两种&#xff1a; 使用数组字面量语法&#xff08;Array Literal Syntax&#xff09;: 使用方括号([])来定义一个新的数组&#xff0c;可以在方括号中添加元素&#xff08;以逗号分隔&#xff09;。 例如&#xff1a; let array1 []; /…

vue引入vuex

Vuex 是 Vue.js 的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。以下是 Vue 中使用 Vuex 的详细步骤&#xff1a; 安装 Vuex&#xff1a; 如果你还没有安装 Vuex&#xff0c;可以通过 npm 或 ya…

利用Github发现优质的学习项目网址

1. 直接搜索&#xff0c;star的数量越多的项目质量越高 2.Github Trending 地址: https://github.com/trending 3. Gitstar Ranking 地址: https://gistar-ranking.com/ 4. Awesome Topic 地址: https://github.com/topics/awesome

[附源码]秦时明月6.2魔改版_搭建架设教程_附GM工具_安卓苹果

本教程仅限学习使用&#xff0c;禁止商用&#xff0c;一切后果与本人无关&#xff0c;此声明具有法律效应&#xff01;&#xff01;&#xff01;&#xff01; 教程是本人亲自搭建成功的&#xff0c;绝对是完整可运行的&#xff0c;踩过的坑都给你们填上了 一. 演示视频 秦时明…

Oracle导入数据中文乱码问题处理,修改客户端字符编码跟数据库的一致

前提&#xff1a;SQL文件打开其中中文字符是正常显示&#xff0c;保证导出文件中文字符正常。通过sqlplus命令导入SQL文件出现乱码&#xff0c;这是因为客户端跟数据库的字符集不一致导致出现乱码问题。 要SQL导入的中文正常&#xff0c;要确保执行导入命令的客户端字符编码跟…

【电路笔记】-Twin-T振荡器

Twin-T振荡器 文章目录 Twin-T振荡器1、概述2、Twin-T振荡器3、Twin-T放大4、Twin-T 振荡器示例5、总结Twin-T 振荡器是另一种 RC 振荡器电路,它使用两个并联的 RC 网络来产生单一频率的正弦输出波形。 1、概述 Twin-T 振荡器是另一种类型的 RC 振荡器,它产生正弦波输出,用…

牛客 二叉树 NB1 牛群的最大高度

原题链接 就不采用, 递归的方式来做了, 自己弄个栈来做 用栈来保存路径, curr 表示当前的节点, pre 保留往回走时的上一步 如果是 用递归来做 它的栈链路是这样的, 可以做下参考 黄色表示返回 用栈模拟的话, 不可能模拟得一摸一样, 递归的话一个栈会经过3次, 第三次后就不…

医学论文摘要翻译 中译英哪里比较专业

论文摘要是对论文内容不加注释和评论的简短陈述&#xff0c;需要扼要说明论文的目的、研究方法和最终结论。在发表学术论文时&#xff0c;很多重要刊物会要求作者将文章的摘要翻译成英文。那么&#xff0c;针对医学论文摘要翻译&#xff0c;中译英哪里比较专业&#xff1f; 专…

【C++】详解STL容器之一的 vector

目录 概述 迭代器 数据结构 优点和缺点 接口介绍 begin end rbegin rend resize reseve insert erase 其他一些接口 模拟实现 框架 获取迭代器 深浅拷贝 赋值重载 reseve resize 拷贝构造 构造 析构 insert erase 其他 概述 vector是STL的容器之一。…

连接docker中的MySQL出现2058错误

出错场景&#xff1a;在虚拟机中用docker技术下载最新版本的MySQL&#xff0c;在本地电脑上连接发现出现2058错误。 解决方法&#xff1a; 按照以下步骤 1. 2. ALTER USER root% IDENTIFIED WITH mysql_native_password BY 自己MySQL的密码; 3.成功

SpringBoot启动类常用注解

1. @SpringBootApplication 这是一个组合注解,包含了@SpringBootConfiguration、@EnableAutoConfiguration和@ComponentScan注解。通常用于标记启动类。 使用@AliasFor注解定义了4个参数,分别是"exclude","excludeName","basePackages",&…

redis--安装

简介 官网&#xff1a;RedisInsight - The Best Redis GUI 各个版本官网下载地址&#xff1a;http://download.redis.io/releases/ Redis和Memcached是非关系型数据库也称为NoSQL数据库&#xff0c;MySQL、Mariadb、SQL Server、PostgreSQL Oracle 数据库属于关系型数据 应用…

为什么选择ATECLOUD自动化测试平台?

在当今飞速发展的时代&#xff0c;一切都在不断进步与变革&#xff0c;电测行业也由手动测试逐步转向了自动化测试。但是随着科技的发展&#xff0c;对于产品的测试要求也越来越高&#xff0c;传统的自动化测试系统已经无法满足用户日益增长的测试需求&#xff0c;全新的ATE测试…

优化理论复习——(四)

无约束优化专题&#xff0c;主要使用了序列无约束极小化方法 无约束优化问题相关解法 最优性条件 互补松弛条件 对于一般约束优化问题&#xff1a; 整理一下就是著名的kkt条件&#xff1a; 这里只需要注意一点&#xff0c;那就是互补松弛条件只对不等式约束有限制。 然后是…

在全志H616核桃派开发板上实现超声波传感器测距

前言​ 超声波传感器是一款测量距离的传感器。其原理是利用声波在遇到障碍物反射接收结合声波在空气中传播的速度计算的得出。在测量、避障小车&#xff0c;无人驾驶等领域都有相关应用。 实验目的​ 通过python编程实现超声波传感器测距。 实验讲解​ 下图是一款市面上常…

【智能算法】雪消融优化算法(SAO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2023年&#xff0c;L Deng受到雪升华和融化行为启发&#xff0c;提出了雪消融优化算法&#xff08;Snow Ablation Optimizer, SAO&#xff09;。 2.算法原理 2.1算法思想 SAO模拟了雪的…

C语言,实现数字谱到简谱的转换(二)

C语言&#xff0c;实现数字谱到简谱的转换&#xff08;二&#xff09; 前言&#xff1a;本文初编辑于2024年5月8日 CSDN&#xff1a;https://blog.csdn.net/rvdgdsva 博客园&#xff1a;https://www.cnblogs.com/hassle 前言 结合前文使用 之前的程序默认C调4/4拍&#xff…