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区分分布式和微服…

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;基…

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

//稳定耗时&#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…

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

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

第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…

机器学习中线性回归算法的推导过程

线性回归是机器学习中监督学习中最基础也是最常用的一种算法。 背景&#xff1a;当我们拿到一堆数据。这堆数据里有参数&#xff0c;有标签。我们将这些数据在坐标系中标出。我们会考虑这些数据是否具有线性关系。简单来说 我们是否可以使用一条线或者一个平面去拟合这些数据的…

如何在交换机上重置密码而不丢失配置?如何配置SSH远程登录?

在网络设备管理中&#xff0c;保持设备的安全性是至关重要的&#xff0c;所以console密码是必须设置的&#xff0c;绝对不能偷懒。 但是&#xff0c;如果习惯不好&#xff0c;或者离职时交接不好&#xff0c;就会导致密码丢失&#xff0c;此时想要修改网络设置的配置就麻烦了。…

华为OD机试 - 符号运算 - 递归(Java 2024 C卷 100分)

华为OD机试 2024C卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试…

使用 FFmpeg 从音视频中提取音频

有时候我们需要从视频文件中提取音频&#xff0c;并保存为一个单独的音频文件&#xff0c;我们可以借助 FFmpeg 来完成这个工作。 一、提取音频&#xff0c;保存为 mp3 文件: 要使用 FFmpeg 从音视频文件中提取音频&#xff0c;并将 ACC 编码的音频转换为 MP3 格式&#xff0…

CNN实现fashion_mnist数据集分类(tensorflow)

1、查看tensorflow版本 import tensorflow as tfprint(Tensorflow Version:{}.format(tf.__version__)) print(tf.config.list_physical_devices())2、加载fashion_mnist数据与预处理 import numpy as np (train_images,train_labels),(test_images,test_labels) tf.keras.d…

Neo4j+LLM+RAG 环境配置报错处理

开发KGLLMRAG程序时遇到以下报错&#xff0c;记录下处理方案&#xff1a; ValueError: Could not use APOC procedures. Please ensure the APOC plugin is installed in Neo4j and that ‘apoc.meta.data()’ is allowed in Neo4j configuration 这个参考文章&#xff1a;link…