c++ BSTree二叉搜索树(附原码)

目录

一、概念

二、基本操作

1、插入

2、中序遍历

3、删除

4、查找

5、总结删除

三、应用场景

四、原码



一、概念

左子树比根小,右子树比根大
意义:最多查找高度次数
不需要排序,就达到了二分查找的效率
同时还弥补了单纯数组的插入删除效率低的问题
其中序遍历,是一个升序,所以也叫做二叉排序树

默认定义,搜索树不允许冗余,搜索树也不允许修改
k模型的搜索树不可以修改,因为修改,那就破坏了搜索树的基本结构
k-v模型的搜索树可以修改,修改val部分,搜索树以key为参考构成搜索树

二、基本操作

1、插入

小的插入左边,大的插入右边

注意,先后插入的顺序不同,会导致树的结构不同

2、中序遍历

中序遍历,需要根节点,但是根节点为私有,怎么办?

1)友元(不推荐)
2)缺省参数、
3)再套一层
什么意思?
将函数设置为私有
再在public部分写一个函数2调用函数1

		//4、中序void Inorder(){_Inorder(_root);cout << endl;}private:void _Inorder( Node* root){if (root == nullptr){return;}_Inorder(root->_left);cout << root->_key << ":" << root->_val << endl;_Inorder(root->_right);}

3、删除

替换法(此处的代码逻辑是右子树的最小节点
左子树的最大节点:保证比所有左子树都大
右子树的最小节点:保证比所有右子树都小
交换,删除
但是左子树的最大节点或者右子树的最小节点并不一定是叶子节点
有可能带有节点,所以,需要特殊判断处理

删一个叶子、带一个孩子、带两个孩子,画图依次判断情况

1、带有一个孩子节点的情况:(顺带没有孩子的也解决了,因为链接的是空)
如果我只有一个右孩子,那就要看我是父节点的左孩子还右孩子,需要判断
父节点链接我的右孩子
如果我只有一个左孩子,同样的道理,父节点链接我的左孩子

2、带有两个孩子的节点的删除
替换法:
左子树的最大节点(最右节点),右子树的最小节点(最左节点)
交换,删除
但是要注意个特殊情况:即左子树没有最大节点,右子树没有最小节点,就要单独判断

还有一个坑:
如果根节点的左子树为空,此删除根节点就会出错,因为根据代码逻辑,此时的根节点已经没有了parent
需要单独判断

4、查找

这个简单

5、总结删除

有两种情况:

1、删除叶子节点

2、删除非叶子节点

1)删除带有一个孩子的节点(左/右)
可以把删除叶子节点一同处理,即叶子节点不需要特殊处理
为什么?删除带有一个孩子的节点
其父节点都要链接上该节点的左孩子/右孩子
如果是叶子节点,那么左孩子/右孩子是空,就直接连接上了

除了以上的正常情况
还需要考虑删除的是根节点
也就是单支树的情况
此时也要特殊处理

2)删除带两个孩子的节点
找右子树的最左边节点
又分两种情况:
a、没有最左节点
b、有最左节点

总之,画图!画图!画图!自己分析。不懂,拿我原码去看,推逻辑,自己手撕一遍,从头到尾。如此,抽丝剥茧,一砖一瓦,焉有不会之理?


三、应用场景


1、k模型
构建一个搜索树
查找一个key在不在搜索树内
例如查找文本错误单词

2、k-v模型(key-val)
通过key查找value
可以统计某个关键词次数


搜索二叉树有一个致命点:
当key为有序,就会构成仅有左子树/右子树(单支)的结构,即退化
因此,又有了AVL树和红黑树,解决左右子树高度平衡的问题,即所谓平衡树

四、原码

#pragma once
#include<iostream>
using namespace std;namespace myspace
{template<class K, class V >struct BSTreeNode{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _val ;BSTreeNode(const K& key, const V& val ):_key(key),_val(val),_left(nullptr),_right(nullptr){}};template<class K, class V>class BSTree{typedef BSTreeNode<K,V> Node;public://1、插入bool insert(const K& key, const V& val = 0){//已经存在节点,返回false,不存在,插入(不冗余)if(_root == nullptr){_root = new Node(key,val);return true;}Node* cur = _root;Node* parent = _root;//根节点不为空while (cur){if (key < cur->_key){parent = cur;cur = cur->_left;}else if(key > cur->_key){parent = cur;cur = cur->_right;}else{return false;}}//找到空节点if (key < parent->_key){parent->_left = new Node(key,val);}else{parent->_right = new Node(key,val);}return true;}//2、删除bool erase(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (key < cur->_key){parent = cur;cur = cur->_left;}else if(key > cur->_key){parent = cur;cur = cur->_right;}else//找到节点{if (cur->_left == nullptr)//左孩子为空{if (cur == _root)//右单支树{_root = cur->_right;}else{if (parent->_left->_key == cur->_key){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;}else if (cur->_right == nullptr)//右孩子为空{if (cur == _root)//左单支树{_root = cur->_left;}else{if (parent->_left->_key == cur->_key){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;}else//两个孩子均不为空{//从cur开始,找右子树的最小,即右子树的最左Node* rightMinparent = cur;Node* rightMin = cur->_right;while (rightMin->_left){rightMinparent = rightMin;rightMin = rightMin->_left;}//到这里,说明找到了rightMinswap(cur->_key,rightMin->_key);if (rightMinparent->_left == rightMin)//正常情况下,存在rightMin{rightMinparent->_left = rightMin->_right;}else//不存在rightMin{rightMinparent->_right = rightMin->_right;}delete rightMin;}return true;}}//走到这里,说明找到空了也没有找到return false;}//3、查找Node* find(const K& key){Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_key == key){return cur;}if (key < cur->_key){parent = cur;cur = cur->_left;}else{parent = cur;cur = cur->_right;}}//走到这里,说明找到空了也没有找到return nullptr;}//4、中序void Inorder(){_Inorder(_root);cout << endl;}private:void _Inorder( Node* root){if (root == nullptr){return;}_Inorder(root->_left);cout << root->_key << ":" << root->_val << endl;_Inorder(root->_right);}private:Node* _root = nullptr;};void BSTreetest1(){BSTree<int, int> bs;bs.insert(1,1);bs.insert(2,2);bs.insert(3,3);bs.insert(3,3);bs.insert(3,3);bs.insert(3,3);bs.insert(3,3);bs.insert(3,3);bs.insert(3,3);bs.insert(4,4);bs.insert(5,99);bs.insert(6,100);bs.Inorder();if (bs.find(100))cout << "存在" << endl;elsecout << "不存在" << endl;}void BSTreetest2()//右子树没有最左节点{BSTree<int, int> bs;bs.insert(10);bs.insert(3);bs.insert(18);bs.insert(2);bs.insert(8);bs.insert(9);bs.insert(12);bs.insert(16);bs.Inorder();bs.erase(3);bs.Inorder();}void BSTreetest3()//右子树有最左节点{BSTree<int, int> bs;bs.insert(10);bs.insert(3);bs.insert(18);bs.insert(2);bs.insert(8);bs.insert(9);bs.insert(12);bs.insert(16);bs.insert(5);bs.insert(6);bs.Inorder();bs.erase(3);bs.Inorder();}void BSTreetest4()//右单支树,{BSTree<int, int> bs;bs.insert(1);bs.insert(2);bs.insert(3);bs.insert(4);bs.Inorder();bs.erase(1);bs.Inorder();}void BSTreetest5()//左单支树,{BSTree<int, int> bs;bs.insert(4);bs.insert(3);bs.insert(2);bs.insert(1);bs.Inorder();bs.erase(1);bs.Inorder();}}

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

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

相关文章

自适应调节Q和R的自适应UKF(AUKF_QR)的MATLAB程序

简述 基于三维模型的UKF&#xff0c;设计一段时间的输入状态误差较大&#xff0c;此时通过对比预测的状态值与观测值的残差&#xff0c;在相应的情况下自适应调节系统协方差Q和观测协方差R&#xff0c;构成自适应无迹卡尔曼滤波&#xff08;AUKF&#xff09;&#xff0c;与传统…

【分布式 | 第五篇】何为分布式?分布式锁?和微服务关系?

文章目录 5.何为分布式&#xff1f;分布式锁&#xff1f;和微服务关系&#xff1f;5.1何为分布式&#xff1f;5.1.1定义5.1.2例子5.1.3优缺点&#xff08;1&#xff09;优点&#xff08;2&#xff09;缺点 5.2何为分布式锁&#xff1f;5.2.1定义5.2.2必要性 5.3区分分布式和微服…

TinyVue 3.15.0 正式发布,推出全新的 Charts 图表组件底座,功能更强、图表更丰富!

你好&#xff0c;我是 Kagol。 我们非常高兴地宣布&#xff0c;2024年4月8日&#xff0c;TinyVue 发布了 v3.15.0 &#x1f389;。 TinyVue 每次大版本发布&#xff0c;都会给大家带来一些实用的新特性&#xff0c;上一个版本我们推出了业界组件库没有的 MindMap 思维导图组件…

zookeeper启动 FAILED TO START

注意&#xff1a;启动zookeeper时&#xff0c;需要使用zkServer.sh start命令将所有主机启动后&#xff0c;再查看状态 如果&#xff0c;启动一台主机&#xff0c;查看当前主机状态&#xff0c;则会报错 如果出错&#xff0c;进入到$ZOOKEEPER_HOME/logs&#xff0c;查看日志 …

LabVIEW智能变电站监控系统设计与实现

LabVIEW智能变电站监控系统设计与实现 随着电力系统和智能化技术的快速发展&#xff0c;建立一个高效、可靠的变电站监控系统显得尤为重要。通过分析变电站监控系统的需求&#xff0c;设计了一个基于LabVIEW软件的监控平台。该平台利用虚拟仪器技术、传感器技术和无线传输技术…

Nginx rewrite项目练习

Nginx rewrite练习 1、访问ip/xcz&#xff0c;返回400状态码&#xff0c;要求用rewrite匹配/xcz a、访问/xcz返回400 b、访问/hello时正常访问xcz.html页面server {listen 192.168.99.137:80;server_name 192.168.99.137;charset utf-8;root /var/www/html;location / {root …

【论文阅读:Towards Efficient Data Valuation Based on the Shapley Value】

基于Shapley值的高校数据价值评估 主要贡献 提出了一系列用于近似计算Shapley值的高效算法。设计了一个算法&#xff0c;通过实现不同模型评估之间的适当信息共享来实现这一目标,该算法具有可证明的误差保证来近似N个数据点的SV&#xff0c;其模型评估数量为 O ( N l o g ( N…

EPICS DataBase详解

1、分布式EPICS设置 1&#xff09; 操作界面&#xff1a;包括shell命令行方式(caget, caput, camonitor等)和图形界面方式(medm, edm, css等)。 2&#xff09;输入输出控制器(IOC) 2、IOC 1) 数据库&#xff1a;数据流&#xff0c;基本上周期运行 2)sequencer&#xff1a;基…

2024年全国保密宣传教育月的主题是()。A.贯彻落实保密法。你我都是护密人B.国家利益高于一切,保密责任重于泰山C.筑牢保密防线,维护国家安全

2024年全国保密宣传教育月的主题是()。点击查看答案 A.贯彻落实保密法。你我都是护密人B.国家利益高于一切&#xff0c;保密责任重于泰山 C.筑牢保密防线&#xff0c;维护国家安全D.共筑保密防线&#xff0c;公民人人有责 坚持不懈开展保密宣传教育&#xff0c;是保密工作实…

插入法(直接/二分/希尔)

//稳定耗时&#xff1a; 双向冒泡&#xff0c;可指定最大最小值个数MaxMinNum<nsizeof(Arr)/sizeof(Arr[0]), void BiBubbleSort(int Arr[],int n&#xff0c;int MaxMinNum){int left0,rightn-1;int i;bool notDone true;int temp;int minPos;while(left<right&&am…

图像处理--空域滤波增强(原理)

一、均值滤波 线性滤波算法&#xff0c;采用的主要是邻域平均法。基本思想是使用几个像素灰度的某种平均值来代替一个原来像素的灰度值。可以新建一个MN的窗口以为中心&#xff0c;这个窗口S就是的邻域。假设新的新的像素灰度值为&#xff0c;则计算公式为 1.1 简单平均法 就是…

LeetCode 234.回文链表

题目描述 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为 回文链表 。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff…

PWN入门之Stack Overflow

Stack Overflow是一种程序的运行时&#xff08;runtime&#xff09;错误&#xff0c;中文翻译过来叫做“栈溢出”。栈溢出原理是指程序向栈中的某个变量中写入的字节数超过了这个变量本身所申请的字节数&#xff0c;导致与其相邻的栈中的变量值被改变。 在本篇文章中&#xff…

常用语音识别开源四大工具:Kaldi,PaddleSpeech,WeNet,EspNet

无论是基于成本效益还是社区支持&#xff0c;我都坚决认为开源才是推动一切应用的动力源泉。下面推荐语音识别开源工具&#xff1a;Kaldi&#xff0c;Paddle&#xff0c;WeNet&#xff0c;EspNet。 1、最成熟的Kaldi 一个广受欢迎的开源语音识别工具&#xff0c;由Daniel Pove…

下一代防火墙是什么?

下一代防火墙(NGFW&#xff0c;Next-Generation Firewall)是一种高级安全设备&#xff0c;它提供了传统防火墙的功能并加入了更多的安全特性&#xff0c;以应对现代复杂网络环境中的安全威胁。NGFW不仅包括基本的数据包过滤功能&#xff0c;还集成了深度包检测(DPI)、入侵防御系…

代码随想录算法训练营DAY54|C++动态规划Part15|647.回文子串、516最长回文子序列、

文章目录 647.回文子串思路CPP代码双指针 516最长回文子序列思路CPP代码 动态规划总结篇 647.回文子串 力扣题目链接 文章链接&#xff1a;647.回文子串 视频链接&#xff1a;动态规划&#xff0c;字符串性质决定了DP数组的定义 | LeetCode&#xff1a;647.回文子串 其实子串问…

fcn网络是怎么学习 时间序列 怎么进行分类的啊 这是我的wave1_test.shape (2904, 3, 8000)

**全卷积网络&#xff08;FCN&#xff09;**处理时间序列数据进行分类的方法主要涉及以下几个步骤&#xff1a; 1. 数据预处理 首先&#xff0c;时间序列数据&#xff08;如你的 wave1_test 形状为 (2904, 3, 8000)&#xff09;需要适当的预处理。这可能包括归一化、去噪等步…

容器下的 Go 应用程序优化

1. 内存对齐 结构体内字段&#xff0c;从大到小排列 减少内存占用 1&#xff09;安装 fieldalignment 工具 go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignmentlatest 2&#xff09;分析并修复内存对齐 fieldalignment -fix ./.../Us…

第07-6章 应用层详解

HTTP、SSL&#xff1a;基于TCP&#xff0c;HTTP端口:80、HTTPS&#xff08;加密&#xff09;端口&#xff1a;443&#xff1b;FTP:基于TCP&#xff0c;两类端口&#xff1a;21、20&#xff08;数据传输之前需要建立连接此时是21&#xff0c;真正传输数据时用20&#xff09;TFTP…

JS基础:常见的6种语句详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端基础路线”&#xff0c;可获取完整web基础…