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

news2025/1/15 19:51:41

一、什么是二叉搜索树

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

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

二、二叉搜索树的操作

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.coloradmin.cn/o/1653935.html

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

相关文章

【Linux】25. 网络基础(一)

网络基础(一) 计算机网络背景 网络发展 独立模式: 计算机之间相互独立; 网络互联: 多台计算机连接在一起, 完成数据共享; 其实本质上一台计算机内部也是一个小型网络结构(如果我们将计算机内部某个硬件不存放在电脑中&#xff0c;而是拉根长长的线进行连接。这其实也就是网…

【Arduino IDE 2】Windows平台安装ESP8266 NodeMCU LittleFS Uploader(文件上传插件)

在Arduino IDE 2&#xff08;2.2.1或更高版本&#xff09;上&#xff0c;如何安装基于ESP8266 NodeMCU的LittleFS文件系统上传插件&#xff0c;以及如何将文件上传到ESP8266 NodeMCU板文件系统。 一、LittleFS简介 LittleFS是一个为微控制器创建的轻量级文件系统&#xff0c;可…

五种算法(BWO、RUN、SO、HO、GWO)求解复杂城市地形下无人机路径规划,可以修改障碍物及起始点(MATLAB)

一、算法介绍 &#xff08;1&#xff09;白鲸优化算法BWO 参考文献&#xff1a;Zhong C, Li G, Meng Z. Beluga whale optimization: A novel nature-inspired metaheuristic algorithm[J]. Knowledge-Based Systems, 2022, 109215. &#xff08;2&#xff09;龙格-库塔优化…

基于Springboot的校园招聘系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园招聘系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

6层板学习笔记1

说明:笔记基于6层全志H3消费电子0.65MM间距BGA 目的:掌握各类接口的布局思路和布线,掌握DDR高速存储设计 1、网表的导入是原理图的元件电气连接关系,位号,封装,名称等参数信息的总和 2、原理图文件包含(历史版本记录,功能总框图,电源树,GPIO分配,DDR功能,CPU,US…

渐进淡出背景个人导航页源码(火影版)

渐进淡出背景个人导航页源码&#xff08;火影版&#xff09; 效果图部分源码领取源码下期更新预报 效果图 部分源码 <!DOCTYPE html> <html> <head> <!--小K网 www.xkwo.com --><meta charset"UTF-8"><title>火影版个人主页<…

连接云服务器中部署的组件,如MySQL、nacos等

作者遇到的问题是在云服务器部署了nacos后&#xff0c;使用 弹性公网IP:8848/nacos来访问nacos中心&#xff0c;但是打不开页面。 解决了这个问题后将解决方法写下来希望帮到大家 这里以作者使用的华为云服务器为例。 首先明确安全组的概念&#xff1a; 系统为每个云服务器默…

内存卡突然罢工?数据恢复有高招!

内存卡作为我们日常生活中常见的存储设备&#xff0c;广泛应用于手机、相机等设备中。然而&#xff0c;有时我们会遇到内存卡损坏打不开的情况&#xff0c;这时该如何应对呢&#xff1f;本文将为您详细解析内存卡损坏的原因&#xff0c;并提供有效的数据恢复方案&#xff0c;帮…

Mysql 基础 - 常见 子句

算数运算符 > < > < !/<> 逻辑运算符 3i in is null is not null 2l limit like 2o or 、order by 1a and ib between and 1n not and、or 、not、 in、 orderby、 limit、 like、 between...and、 is null 、is not null

四级英语翻译随堂笔记

降维表达&#xff1a;中译英&#xff0c;英译英 没有强调主语&#xff0c;没有说明主语&#xff1a;用被动 但如果实在不行&#xff0c;再增添主语 不会就不翻译&#xff0c;不要乱翻译 以xxx为背景&#xff1a;against the backdrop of the xxx eg:against the backdrop of…

javax.net.ssl.SSLException: Received fatal alert: protocol_version已经解决

起因&#xff1a; 在帮别人讲解项目时&#xff0c;将项目的tomcat配置完&#xff0c;点击运行后&#xff0c;报错&#xff0c;信息如标题。 解决办法&#xff1a; 在csdn百度问题&#xff0c;得到的方法主要有几个&#xff1a; 1.jdk要配置在1.8以上&#xff1b; 2.数据库地…

关系型数据库MySQL开发要点之多表查询2024详解

多表查询 准备测试数据 -- 部门管理 create table tb_dept(id int unsigned primary key auto_increment comment 主键ID,name varchar(10) not null unique comment 部门名称,create_time datetime not null comment 创建时间,update_time datetime not null comment 修改时…

改进灰狼算法优化随机森林回归预测

灰狼算法&#xff08;Grey Wolf Optimization&#xff0c;GWO&#xff09;是一种基于自然界灰狼行为的启发式优化算法&#xff0c;在2014年被提出。该算法模仿了灰狼群体中不同等级的灰狼间的优势竞争和合作行为&#xff0c;通过不断搜索最优解来解决复杂的优化问题。 灰狼算法…

HawkEye—高效、细粒度的大页管理算法

文章目录 HawkEye—高效、细粒度的大页管理算法1.作者简介2.文章简介与摘要3.简介(1).当时的SOTA系统概述LinuxFreeBSDIngens (2).HawkEye 4.动机(1).地址翻译开销与内存膨胀(2).缺页中断延迟与缺页中断次数(3).多处理器大页面分配(4).如何测算地址翻译开销&#xff1f; 5.设计…

Windows安全加固-账号与口令管理

在当今日益增长的网络安全威胁中&#xff0c;Windows系统的安全加固显得尤为重要。其中&#xff0c;账号与口令管理作为系统安全的第一道防线&#xff0c;其重要性不言而喻。本文将深入探讨Windows安全加固中的账号与口令管理策略&#xff0c;以确保系统的安全性和稳定性。 账…

FTTR(光猫)ITMS注册NCE纳管

ITMS注册 TR069交互过程&#xff1a; 1.1. TR069交互—主动连接机制 主动连接机制是指CPE主动发出请求连接事件(事件可以为&#xff1a; 0 BOOTSTRAP&#xff1b; 1 BOOT; PERIODIC等等)给ACS。在连接建立之后才能进行业务处理(通过调用RPC方法实现)。 备注&#xff1a;政企…

支持LLM的Markdown笔记;ComfyUI-HiDiffusion图片生成和对图像进行高质量编辑

✨ 1: ComfyUI-HiDiffusion ComfyUI-HiDiffusion是一个为HiDiffusion技术使用而定制的节点。HiDiffusion技术是专门用于在计算机视觉和图像处理中生成和改进图片质量的先进算法。该技术通常应用于图像的超分辨率、去噪、风格转换等方面。 ComfyUI-HiDiffusion的主要特点包含提…

邦注科技给您解答 什么是注塑机模具保护器

模具监视器&#xff0c;这位制造业的守护神&#xff0c;时刻注视着模具的每一个细微变化。它的工作原理如同一位细心的侦探&#xff0c;利用传感器、数据采集系统和监控软件组成的精良装备&#xff0c;探寻模具的秘密。 传感器如同模具的耳目&#xff0c;敏锐地捕捉着模具的温度…

4.6_shell中的运算

##1.运算符号## ##加法 - ##减法 * ##乘法 / ##除法 % ##除法后的余数 ** ##乘方 ##自加一 -- ##自减一 < ##小于 > ##大于 > ##大于等与 < ##小于等于 ji ##jji * ##jj*i / ##jj/i % ##jj%i ##2.运算指令## …

基于Vumat的修正JC本构模型的切削研究

JC渐进损伤本构是研究切削中的重要本构模型&#xff0c;主要包括材料硬化和损伤两部分&#xff1a;其中&#xff0c;原始JC的硬化部分本构为&#xff1b; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 材料屈服应力的硬化解耦为三部分独立的效应&#x…