【1++的数据结构】之二叉搜索树

news2025/1/11 2:17:06

👍作者主页:进击的1++
🤩 专栏链接:【1++的数据结构】


文章目录

  • 一,什么是二叉搜索树
  • 二,二叉搜索树的操作及其实现
    • 2.1 插入操作及其实现
    • 2.2 查找操作及其实现
    • 2.3 删除操作及其实现
  • 三,构造及其析构
  • 四,二叉搜索树的应用

在这里插入图片描述

一,什么是二叉搜索树

二叉搜索书又叫二叉排序树或二叉查找树,其左子数上的节点小于根节点;右子树上的节点大于根节点。
如图,就是一颗二叉搜索树。
在这里插入图片描述

二,二叉搜索树的操作及其实现

2.1 插入操作及其实现

二叉搜索树的插入其先根据插入值的大小确定插入的位置,并且,若是有相同的值则不会进行插入。确定位置的依据是我们上述的二叉搜索树的特性:左子树上的节点小于根节点;右子树上的节点大于根节点。
当确定好位置后,我们申请节点,将新节点链接到树中。
下面是插入的两种实现:

  1. 非递归:
typedef BSTreeNode<K> Node;
	public:
		bool Insert(const K& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}
			Node* cur = _root;
			Node* parent = _root;//记录其父节点,方便链接
			while (cur != nullptr)//找位置
			{
				if (key < cur->_key)
				{
					parent = cur;
					cur = cur->left;
				}
				else if (key > cur->_key)
				{
					parent = cur;
					cur = cur->right;
				}
				else
				{
					return false;
				}
			}

			cur = new Node(key);
			//链接过程
			if (parent->_key > key)
			{
				parent->left = cur;
			}
			else
			{
				parent->right = cur;
			}
			return true;

		}
  1. 递归
	bool InsertR(const K& key)
		{
			return _InsertR(_root, key);
		}

   bool _InsertR(Node*& root,const K& key)
		{
			if (root == nullptr)//为空则说明已经找好了位置,可以进行插入
			{
				Node* cur = new Node(key);
				root = cur;
				return true;
			}
			if (key < root->_key)
			{
				_InsertR(root->left, key);
			}
			else if (key > root->_key)
			{
				_InsertR(root->right, key);
			}
			else
			{
				return false;//遇到相同的值
			}
			return true;

		}

由于在类外无法访问根节点_root,所以无法给_InsertR()传参,因此我们,多写了一层函数,在类里面调用插入的递归函数。这里有一个非常重要的细节就是在传root时我们使用的是引用。这时我们就可以直接进行链接,不需要记录其父节点了。

2.2 查找操作及其实现

其查找利用其二叉搜索树的特性,当树为完全二叉树或满二叉树时,其效率可以达到lgN (N为数的高度)。
下面为查找的两种实现方法:

  1. 非递归:
bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (key < cur->_key)
				{
					cur = cur->left;
				}
				else if (key > cur->_key)
				{
					cur = cur->right;
				}
				else
				{
					return true;
				}
			}
			return false;
		}
  1. 递归实现

	bool _FindR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}
			if (key < root->_key)
			{
				_FindR(root->left, key);
			}
			else if (key > root->_key)
			{
				_FindR(root->right, key);

			}
			else
			{
				return true;
			}
		}

2.3 删除操作及其实现

删除操作我们可以分为几种情况:

  1. 删除节点没有孩子
  2. 删除节点有右孩子
  3. 删除节点有左孩子
  4. 删除节点有左右孩子
    对这四种情况我们又可以进行合并,将1与2,3归为一类。
    对于有两个节点的情况,我们在找到要删除节点后,在找到右子树的最小值或左子树的最大值,将其值与删除节点值进行交换,这时,我们就只需要删除右子树最小值或左子树最大值了。
    需要注意的是:其右子树最小值或左子树最大值后可能还有节点,因此要进行判断。

非递归:

bool Erase(const K& key)
		{
			Node* cur = _root;
			Node* parent = _root;
			while (cur != nullptr)
			{
				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 (key < parent->_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 (key < parent->_key)
						{
							parent->left = cur->left;
						}
						else
						{
							parent->right = cur->left;
						}

						delete cur;
					}
					else//都不为空
					{
						//先找右子树的最小值
						Node* Minparent = cur;
						Node* Min=cur->right;
						while (Min->left != nullptr)
						{
							Minparent = Min; 
							Min = Min->left;
						}
						std::swap(Min->_key, cur->_key);
						if (Minparent->left == Min)
						{
							Minparent->left = Min->right;
						}
						else
						{
							Minparent->right = Min->right;
						}
						delete Min;

					}
					return true;
						
				}
			}
			return false;
		}
		

递归:

	bool _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}
			if (key < root->_key)
			{
				_EraseR(root->left, key);
			}
			else if (key > root->_key)
			{
				_EraseR(root->right, key);
			}
			else
			{
				Node* del = root;
				//找右子树最小
				if (root->left == nullptr)
				{
					root = root->right;
				}
				else if (root->right == nullptr)
				{
					root = root->left;
				}
				else
				{
					Node* min = root->right;
					//找右子树最小值
					while (min->left)
					{
						min = min->left;
					}
					std::swap(root->_key, min->_key);
					return _EraseR(root->right, key);

				}
				delete del;
				return true;
			}
		}

三,构造及其析构

//拷贝构造
       BSTree(const BSTree<K>& t)
		{
			_root = Copy_root(t._root);

		}

       Node* Copy_root(Node* root)
		{
			if (root == nullptr)
			{
				return nullptr;
			}
			Node* copy_root = new Node(root->_key);
			copy_root->left = Copy_root(root->left);
			copy_root->right = Copy_root(root->right);
			return copy_root;
		}

//赋值重载
		BSTree& operator=(BSTree<K> T)
		{
			std::swap(T._root,this->_root);
			return *this;
		}

//析构

	~BSTree()
		{
			Destory(_root);
		}

  void Destory(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			Destory(root->left);
			Destory(root->right);
			delete root;
			root = nullptr;
		}

拷贝构造有一些像前序遍历,我们遇到一个节点就构造一个节点,最后在递归返回时将其链接起来。
析构函数则是像后续遍历。

四,二叉搜索树的应用

  1. K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
  2. KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。如,中英文对照。

二叉搜索树的性能:对于插入和删除来说,都必须要先查找:插入查找插入的位置,删除查找删除的节点。因此其查找的性能代表了二叉树的性能。其查找的性能于树的深度有关,但对于同一个集合,其插入的顺序不同,那么形成的树也是不同的。我们期望的最好的情况是它能够形成一个完全二叉树或接近完全二叉树的树。此时他的查找的效率能够达到lgN;但其也有可能会形成一个单支树,此时效率最差,为N。
在这里插入图片描述

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

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

相关文章

docker版jxTMS使用指南:使用jxTMS采集数据之一

本文讲解了如何jxTMS的数据采集与处理框架并介绍了如何用来采集数据&#xff0c;整个系列的文章请查看&#xff1a;docker版jxTMS使用指南&#xff1a;4.4版升级内容 docker版本的使用&#xff0c;请查看&#xff1a;docker版jxTMS使用指南 4.0版jxTMS的说明&#xff0c;请查…

【搭建PyTorch神经网络进行气温预测】

import numpy as np import pandas as pd import matplotlib.pyplot as plt import torch import torch.optim as optim import warnings warnings.filterwarnings("ignore") %matplotlib inlinefeatures pd.read_csv(temps.csv)#看看数据长什么样子 features.head…

图像 分割 - Fast-SCNN: Fast Semantic Segmentation Network (arXiv 2019)

Fast-SCNN: Fast Semantic Segmentation Network - 快速语义分割网络&#xff08;arXiv 2019&#xff09; 摘要1. 引言2. 相关工作2.1 语义分割的基础2.2 DCNN的效率2.3 辅助任务预训练 3. 提议的Fast-SCNN3.1 动机3.2 网络架构3.2.1 学习下采样3.2.2 全局特征提取器3.2.3 特征…

侯捷 C++面向对象编程笔记——10 继承与虚函数

10 继承与虚函数 10.1 Inheritance 继承 语法&#xff1a;:public base_class_name public 只是一种继承的方式&#xff0c;还有protect&#xff0c;private 子类会拥有自己的以及父类的数据 10.1.1 继承下的构造和析构 与复合下的构造和析构相似 构造是由内而外 Container …

试图将更改推送到 GitHub,但是远程仓库已经包含了您本地没有的工作(可能是其他人提交的修改)

这通常是由于其他人或其他仓库推送到了相同的分支上&#xff0c;导致您的本地仓库和远程仓库之间存在冲突。 错误信息&#xff1a; To github.com:8upersaiyan/CKmuduo.git ! [rejected] main -> main (fetch first) error: failed to push some refs to github.com:8upers…

Webots与MATLAB联合仿真环境配置

1. 版本 系统&#xff1a;Win10 matlab版本&#xff1a;2023a webots版本&#xff1a;R2020b 2.安装 MATLAB MinGW-w64 C/C Compiler 在使用matlab写控制器之前&#xff0c;需要给matlab安装 MATLAB MinGW-w64 C/C Compiler&#xff0c;因为需要matlab与c进行交互。 下载地址…

K8S系列文章之 Kind 部署K8S的 服务发布

安装kind 下载 https://github.com/kubernetes-sigs/kind/releases/download/0.17.0/kind-linux-amd64 执行以下命令&#xff1a; mv kind-linux-amd64 /usr/local/bin/kind chmod 777 /usr/local/bin/kind 之前需要先在本地主机安装好docker yum -y install yum-utils d…

门面模式(C++)

定义 为子系统中的一组接口提供一个一致(稳定) 的界面&#xff0c;Facade模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用(复用)。 应用场景 上述A方案的问题在于组件的客户和组件中各种复杂的子系统有了过多的耦合&#xff0c;随着外部客户程序和各子…

无锚框原理 TOOD:Task-aligned One-stage Object Detection

无锚框原理 TOOD&#xff1a;Task-aligned One-stage Object Detection 一 摘要二 引言TOOD设计 三 具体设计Task-aligned Head任务对齐的预测器 TAP预测对齐 TAL 任务对齐学习Task-aligned Sample Assignment多任务损失 一 摘要 一阶段目标检测通常通过优化两个子任务来实现&…

计算机毕业设计题目大全(论文+源码)_kaic

图书信息管理系统的设计与实现(论文源码)_kaic 基于Spring Boot的学院宿舍管理系统的设计与实现(论文源码)_kaic 在线考试系统设计与实现(论文源码)_kaic 基于javaee的就业管理系统设计与实现(论文源码)_kaic 基于VUE和SpringBoot的微信小程序商城的设计与实现(论文源码)_kaic …

iOS - 开发者账号续订会员资格更换订阅的账号

文章目录 前言开发环境续订会员资格转让账户持有人验证身份1. 实名认证2. 联系信息 更换订阅的账号最后 前言 公司有一个开发者账号快到期了需要续订会员资格&#xff0c;刚注册时是用我自己的个人账号完成的订阅购买。现在想来有点不妥&#xff0c;于是尝试更换用于订阅的账号…

STM32 CubeMX USB_MSC(存储设备U盘)

STM32 CubeMX STM32 CubeMX USB_MSC(存储设备U盘&#xff09; STM32 CubeMX前言 《使用内部Flash》——U盘一、STM32 CubeMX 设置USB时钟设置USB使能UBS功能选择FATFS功能 二、代码部分修改代码"usbd_storage_if.c"修改代码"user_diskio.c"main函数初始化插…

CVE-2022-23134(Zabbix setup 访问控制登录绕过)

目录 一、题目 二、进入题目 一、题目 靶标介绍&#xff1a; Zabbix Sia Zabbix是拉脱维亚Zabbix SIA&#xff08;Zabbix Sia&#xff09;公司的一套开源的监控系统。该系统支持网络监控、服务器监控、云监控和应用监控等。 Zabbix 存在安全漏洞&#xff0c;该漏洞源于在初始…

【VSCode】报错:出现段错误解决办法 (Segmentation fault)

VScode报错&#xff1a;Segmentation fault (core dumped)的解决办法 解决Program received signal SIGSEGV, Segmentation fault.的辛酸 Linux环境下段错误的产生原因及调试方法小结 Linux下的段错误Segmentationfault产生的原因及调试方法经典.pdf 解决办法&#xff1a;

C高级第四讲

1、思维导图 2、写一个shell函数&#xff0c;获取用户的uid和gid并使用变量接收 #!/bin/bash function get_id() {uidid -u ubuntugidid -g ubuntu } get_id echo "uid:$uid" echo "gid:$gid"运行结果 3、排序 冒泡排序 /* ------------------------…

【MongoDB】初识、安装MongoDB

目录 一、MongoDB主要应用场景 二、MongoDB简介 三、MongoDB相关特点 四、MongoDB的安装 一、MongoDB主要应用场景 传统的数据库如MySQL在应对三高场景时显得力不从心 三高&#xff1a; High performance 对数据库高并发读写的需求 High Storage 对海量数据的高效率存储和 …

hacksudo3 通关详解

环境配置 一开始桥接错网卡了 搞了半天 改回来就行了 信息收集 漏洞发现 扫个目录 大概看了一眼没什么有用的信息 然后对着login.php跑了一下弱口令 sqlmap 都没跑出来 那么利用点应该不在这 考虑到之前有过dirsearch字典太小扫不到东西的经历 换个gobuster扫一下 先看看g…

全面的可见性是有效检测和响应威胁的基础

当今的企业比以往任何时候都更加依赖技术&#xff0c;因此强大的威胁检测和响应策略至关重要。现代世界中的网络犯罪分子一直在寻找新的创造性方法来入侵组织网络并窃取敏感数据。全面的可见性是一个关键因素&#xff0c;有时很少受到关注&#xff0c;但它是有效威胁检测和响应…

24届近5年江南大学自动化考研院校分析

今天给大家带来的是江南大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、江南大学 学校简介 江南大学&#xff08;Jiangnan University&#xff09;是国家“双一流”建设高校&#xff0c;“211工程”、“985工程优势学科创新平台”重点建设高校&#xff0c;入选…

Xcode升级导致关联库报错

想办法找到对应的库 然后到 Build Phases -- LinkBinary With Libraries中点击&#xff0c;选择对应的framework即可&#xff0c;就像我工程的报错 Undefined symbol: _OBJC_CLASS_$_ADClient _OBJC_CLASS_$_ASIdentifierManager 缺失的库是AdSupport.framework 添加后再次编…