C++: 二叉搜索树及实现

目录

一、二叉搜索树的概念

二、二叉搜索树的操作

2.1插入

2.2删除

1.有左子树,无右子树

2.有右子树,无左子树

3.有左子树和右子树

三、二叉搜索树的实现

要点


前言:为了学习map和set,需要先学二叉搜索树作为铺垫。

一、二叉搜索树的概念

二叉搜索树是一棵二叉树,又称为二叉排序树,它有以下特性:

1.若左子树不为空,则左子树的节点值比根要小

2.若右子树不为空,则右子树的节点值比根要大

3.整棵树都遵循以上规则

需要注意,二叉树也可以是空树。

二、二叉搜索树的操作

2.1插入

插入的思路是,先用递归将树搜索一遍,用key和树的根的节点比大小,比它大往右走,比它小往左走,直到走到空,那么就在空的位置插入。

2.2删除

删除的思路比较复杂。删除情况分三种,分别是所要删除的节点情况,若删除的是key节点:

1.有左子树,无右子树

这里就将key节点的前一个节点,指向它的后一个节点,然后释放key节点。

2.有右子树,无左子树

和上面类似。

3.有左子树和右子树

这里比较复杂,需要将key节点与它的左子树中的最大的一个,或者右子树中最小的一个交换,然后再删除key。

右子树中最小的一个,是第一个右节点的最左的节点。若没有最左节点,那就只能和右节点交换。

交换以后,就可以删除key节点也就是4了。

最后一种无左子树也无右子树可以放在1和2中讨论,归为一种。操作比较简单,此处不再赘述。

三、二叉搜索树的实现

要点

1.为了体现封装,我们只留接口放在类的public中,把具体实现的细节放在private中,这样也方便代码日后维护。同时由于使用递归,所以需要取root的引用,参数就要给root,而在类外是没有办法获取作为私有的root的,因此只能把实现的细节写在private里。

2.搜索二叉树可以用来匹配,比如说当字典使用和门禁系统,这里可以再放入一个类模板。

3.插入的时候要新建一个节点再插入,这里会改变root的地址,所以传引用会更好,不然就要传二级指针了,这个很麻烦,而且在C++中是避免的。

4.删除的时候,要先找到这个节点,再删除。删除时,一共涉及三个指针的操作。建议先理清思路再写代码。

namespace ting
{
	template<class K, class V>
	struct BSTreeNode
	{
		BSTreeNode(const K& content, const V& value)
			:_content(content)
			,_left(nullptr)
			,_right(nullptr)
			,_value(value)
		{

		}
		K  _content;
		BSTreeNode<K,V>* _left;
		BSTreeNode<K,V>* _right;

		V _value;
	};
	template<class K, class V>
	class BSTree
	{
		typedef BSTreeNode<K, V> Node;
	public:

		bool Insert(const K& key, const V& value)
		{
			return _Insert(_root, key, value);
		}
		Node* Find(const K& key)
		{
			return _Find(_root, key);
		}

		bool Erase(const K& key)
		{
			return _Erase(_root, key);
		}
		
		void InOrder()
		{
			_InOrder(_root);
		}
		
	private:
		Node* _root = nullptr;

		Node* _Find(Node* root, const K& key)
		{
			while (root != nullptr)
			{
				if (root->_content < key)
				{
					root = root->_right;
				}
				else if (root->_content > key)
				{
					root = root->_left;
				}
				else if (root->_content == key)
				{
					return root;
				}
			}
			return nullptr;
		}

		void _InOrder(Node* root)
		{
			if (root == nullptr)
				return;
			_InOrder(root->_left);
			cout << root->_content<<" "<<root->_value << endl;
			_InOrder(root->_right);
		}


		bool _Insert(Node*& root, const K& key, const V& value)
		{
			if (root == nullptr)
			{
				/*root->_content = key;
				root->_value = value;
				return true;*/
				root = new Node(key, value);//这里要给root建一个节点
				return true;
			}
			
			if (root->_content < key)
			{
				return _Insert(root->_right, key, value);
			}
			else if (root->_content > key)
			{
				return _Insert(root->_left, key, value);
			}
			else
			{
				return false;
			}
		}

		bool _Erase(Node*& root, const K& key)
		{
			if (root == nullptr)
				return false;
			
			if (root->_content < key)
			{
				return _Erase(root->_right, key);
			}
			else if (root->_content > key)
			{
				return _Erase(root->_left, key);
			}
			else
			{
				Node* del = root;
				if (root->_left == nullptr)
				{
					root = root->_right;
				}
				else if (root->_right == nullptr)
				{
					root = root->_left;
				}
				else
				{
					Node* prev = root;
					Node* minNode = root->_right;
					while (minNode->_left != nullptr)
					{
						prev = minNode;
						minNode = minNode->_left;
					}

					root->_content = minNode->_content;
					root->_value = minNode->_value;

					if (prev->_left == minNode)
					{
						prev->_left = minNode->_right;
					}
					else
					{
						prev->_right = minNode->_right;
					}

					del = minNode;
				}
				delete del;
				return true;		
			}

		}
	};

	void TestBSTree()
	{
		BSTree<string, string> dict;
		dict.Insert("insert", "插入");
		dict.Insert("erase", "删除");
		dict.Insert("left", "左边");
		dict.Insert("string", "字符串");

		string str;
		while (cin >> str)
		{
			auto ret = dict.Find(str);
			if (ret)
			{
				cout << str << ":" << ret->_value << endl;
			}
			else
			{
				cout << "单词拼写错误" << endl;
			}
		}

		string strs[] = { "苹果", "西瓜", "苹果", "樱桃", "苹果", "樱桃", "苹果", "樱桃", "苹果" };
		// 统计水果出现的次
		BSTree<string, int> countTree;
		for (auto str : strs)
		{
			auto ret = countTree.Find(str);
			if (ret == NULL)
			{
				countTree.Insert(str, 1);
			}
			else
			{
				ret->_value++;
			}
		}
		countTree.InOrder();
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【quarkus系列】创建quarkus第一个应用程序

文章目录 序言环境准备创建项目项目分析程序代码构建访问项目 序言 Quarkus 是一个设计用于 Kubernetes 和云原生环境的 Java 框架&#xff0c;具有快速启动时间、低内存消耗和强大的开发者体验。溪源将带您一步步创建一个简单的 Quarkus 应用程序。 环境准备 在开始之前&am…

【UE5.1 角色练习】06-角色发射火球-part1

前言 在上一篇&#xff08;【UE5.1 角色练习】05-火球发射物-CSDN博客&#xff09;基础上实现角色可以发射火球的技能 效果 步骤 一、准备 1. 打开角色蓝图&#xff0c;添加两个浮点型变量&#xff0c;分别表示当前的MP值和满状态的MP值 添加一个函数&#xff0c;这里命名…

链表经典题目—相交链表和链表倒数第k个节点

&#x1f389;&#x1f389;&#x1f389;欢迎莅临我的博客空间&#xff0c;我是池央&#xff0c;一个对C和数据结构怀有无限热忱的探索者。&#x1f64c; &#x1f338;&#x1f338;&#x1f338;这里是我分享C/C编程、数据结构应用的乐园✨ &#x1f388;&#x1f388;&…

postman教程-4-发送post请求

领取资料&#xff0c;咨询答疑&#xff0c;请➕wei: June__Go 上一小节我们学习了postman发送get请求的方法&#xff0c;本小节我们讲解一下postman发送post请求的方法。 POST请求通常用于向服务器提交数据以创建新资源或执行某些操作。与GET请求不同&#xff0c;POST请求可…

JMeter 测试单节点与集群的并发异常率

一. JMeter 测试单节点与集群的并发异常率 下载地址&#xff1a;https://jmeter.apache.org/download_jmeter.cgi 单个tomcat测试结果(2000个用户&#xff0c;每个用户访问100次) nginx集群负载均衡tomcat结果(2000个用户&#xff0c;每个用户访问100次)

Unity 生成物体的几种方式

系列文章目录 unity工具 文章目录 系列文章目录前言&#x1f449;一、直接new的方式创建生成1-1.代码如下1-2. 效果图 &#x1f449;二、使用Instantiate创建生成&#xff08;GameObject&#xff09;2-1.代码如下2-2.效果如下图 &#x1f449;三.系统CreatePrimitive创建生成3…

STM32Cube系列教程10:STM32CubeIDE工程创建+串口DMA+IDLE+printf重定向+软中断处理串口数据+非阻塞延时任务

文章目录 工程配置配置时钟配置Debug接口配置串口外设配置时钟树生成代码 配置串口重定向printf配置串口&#xff0c;开启IDLE&#xff0c;开启软中断 配置非阻塞延时任务调度函数编写任务调度函数延时任务创建 编译&#xff0c;下载与测试编译下载测试 前两天收到了ST社区的NU…

最后7天,高考翻盘秘籍等你开启!

高考&#xff0c;这场关乎未来的考试&#xff0c;对于每一个学生来说都是一次严峻的挑战。随着倒计时的进行&#xff0c;无数考生和家长的焦虑和期待达到了顶点。在这个最后7天的关键时期&#xff0c;我们为即将参加高考的学生及其家长提供一份复习秘籍&#xff0c;帮助你们抓住…

【CSP CCF记录】201912-1 报数

题目 代码 首先判断是否为7的倍数&#xff0c;其次判断各位数是否有7 #include<bits/stdc.h> using namespace std; int n; int main() {cin>>n;int num[4]{0};for(int i1;i<n;i){int j(i-1)%4;if(i%70){num[j];n;continue;} int tempi;while(temp/10>0||t…

Word整理论文参考文献

1.安装Zotero软件 2.安装Zotero的Chrome网站插件&#xff0c;并将插件固定到浏览器 3.安装Word的Zotero插件 4.在DBLP网站https://dblp.org/search 搜索需要添加的参考文献->点击BibTex->点击网页右上角的Zotero符号&#xff08;即第二步所指的符号&#xff09;->至…

2023idea没有VCS首次提交代码到Git

1、setting 2、vcs------>create git repository 3、右键项目----->Git------>add 4、右键项目------>git------>commit Directory 之后就会显示这个页面(下面写你提交的信息&#xff0c;就是你修改了什么) 点击commit,提交 5、Git--------->push 6、选择…

华为实训课笔记 2024

华为实训 5/205/215/225/235/27 5/20 5/21 5/22 5/23 5/27

如果任务过多,队列积压怎么处理?

如果任务过多,队列积压怎么处理? 1、内存队列满了应该怎么办2、问题要治本——发短信导致吞吐量降低的问题不能忽略!!3、多路复用IO模型的核心组件简介1、内存队列满了应该怎么办 如图: 大家可以看到,虽然现在发短信和广告投递,彼此之间的执行效率不受彼此影响,但是请…

1、pikachu靶场之xss钓鱼复现

一、复现过程 1、payload <script src"http://127.0.0.1/pkxss/xfish/fish.php"></script> 将这段代码插入到含有储存xss的网页上&#xff0c;如下留言板 2、此时恶意代码已经存入数据库&#xff0c;并存在网页中&#xff0c;当另一个用户打开这个网页…

Qt自定义标题栏

效果如下&#xff1a; 代码如下&#xff1a; // widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr…

国内AI大模型的下半场-「百模大战免费篇」上线,让我们直接梦回十年前

| 我们正在经历第九次「烧钱」大战。 这个故事&#xff0c;大概要从2024年5月6号&#xff0c;一个叫DeepSeek-V2的模型开始说起。 那一天&#xff0c;DeepSeek宣布开源他们的第二代MoE大模型——DeepSeek-V2。根据披露的信息显示&#xff0c;该模型在性能上比肩GPT-4 Turbo。刚…

在Bash中解析命令行参数的两种样例脚本

文章目录 问题回答以空格分隔选项和参数以等号分隔选项和参数 参考 问题 假设&#xff0c;我有一个脚本&#xff0c;它会被这样一行调用: ./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile或者这个&#xff1a; ./myscript -v -f -d -o /fizz/someOtherFile ./fo…

YOLOv8+PyQt5面部表情检测系统完整资源集合(yolov8模型,从图像、视频和摄像头三种路径识别检测,包含登陆页面、注册页面和检测页面)

1.资源包含可视化的面部表情检测系统&#xff0c;基于最新的YOLOv8训练的面部表情检测模型&#xff0c;和基于PyQt5制作的可视化面部表情检测系统&#xff0c;包含登陆页面、注册页面和检测页面&#xff0c;该系统可自动检测和识别图片或视频当中出现的八类面部表情&#xff1a…

【UE5.1 角色练习】08-物体抬升、抛出技能

前言 在上一篇&#xff08;【UE5.1 角色练习】08-传送技能&#xff09;的基础上继续实现控制物体抬升、抛出的功能。 效果 步骤 一、准备技能动画 1. 在项目设置中新建一个操作映射&#xff0c;这里命名为“Skill_GravityControl”&#xff0c;用按键4触发 2. 通过IK重定向…

利用ArcGIS Python批量拼接遥感影像(arcpy batch processing)

本篇文章将说明如何利用ArcGIS 10.1自带的Python IDLE进行遥感影像的批量拼接与裁剪。 1.运行环境&#xff1a;ArcGIS10.1 (安装传送门)、Python IDLE 2.数据来源&#xff1a;地理空间数据云 GDEMV2 30M分辨率数字高程数据 3.解决问题&#xff1a;制作山西省的DEM影像 如下…