搜索二叉树详解

news2024/11/17 20:44:26

🧸🧸🧸各位大佬大家好,我是猪皮兄弟🧸🧸🧸
在这里插入图片描述

文章目录

  • 一、搜索二叉树框架
  • 二、搜索二叉树概念
  • 三、搜索二叉树操作
    • ①Erase
    • ②Find递归
    • ③Insert递归
    • ④Erase递归,比Erase更简洁
    • ⑤析构函数
    • ⑥搜索二叉树的拷贝
    • ⑦赋值运算符重载
  • 四、搜索二叉树存在的问题

一、搜索二叉树框架

	template<class K>
	struct BSTreeNode
	{
		BSTreeNode<K>* _left;
		BSTreeNode<K>* _right;
		K _key;
		BSTreeNode(const K& key)
			:_key(key)
			, _left(nullptr)
			, _right(nullptr)
		{}

	};

	template<class K>//key
	class BSTree
	{
		typedef BSTreeNode<K> Node;
		//...
		Node* _root = nullptr;
	};

二、搜索二叉树概念

搜索二叉树又称二叉搜索树,或者是一颗空树,或者是具有以下性质的二叉树
①若它的左子树不为空,则左子树上所有结点的值都小于根结点
②若它的右子树不为空,则右子树上所有结点的值都大于根结点
③它的左右子树,也分别是搜索二叉树

在这里插入图片描述
也就是找小往左边走,找大往右边走,二叉搜索树最大的价值就是用于搜索,搜索二叉树最多查找高度次,因为搜索二叉树中序遍历就是已排序的数列,所以也叫二叉排序树,如上图的中序遍历结果 1 3 4 6 7 8 10 13 14
另外,搜索二叉树是不能有相同键值的,遇到相同键值不存储,搜索二叉树除了搜索外,顺带的功能就是排序+去重

中序遍历:

//...
public:
void InOrder()
{
	InOrder(_root);
}
private:
void InOrder(Node*root)
{
	if(root->left ==nullptr) return;
	InOrder(root->left);
	cout<<root->_key<<" ";
	InOrder(root->right);
}

三、搜索二叉树操作

普通的插入删除查找等等我就不写了

①Erase

在这里插入图片描述
删除结点只有一个孩子的话直接交给父节点即可,比如上面删除14,直接给10这种情况有一个特例,就是删除根的时候,只有一个孩子的话,直接将root转移给孩子即可

但是当该结点有两个孩子呢?比如删除上面的6
这种情况需要用到替换法,替换有两种方式,因为搜索二叉树的左<根<右
所以
①找到该节点左子树的最右,也就是最大结点进行替换,要保证搜索二叉树的特性
②找到该节点右子树的最左,也就是 最小结点进行替换

//Erase代码
bool Erase(const K&key)
{
	Node*cur = _root;//根
	Node*parent = cur;
	while(cur)
	{
		if(cur->val<key)
		{
			cur=cur->_right;
			parent = cur;
		}
		else if(cur->val>key)
		{	
			cur=cur->_left;
			parent = cur;
		}
		else
		{
			//三种情况
			//一个孩子&&根   一个孩子&&非根   两个孩子
			if(cur->_left ==nullptr)
			{
				if(cur==_root)
				{	//_root转移
					_root = cur->_right;
				}
				else
				{
					if(cur==parent->_left)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;
					}
					//需要找父节点,所以提前找好
					delete cur;
					cur=nullptr;//习惯
				}
			}
			else if(cur->_right==nullptr)
			{
					if(cur==_root)
					{	//_root转移
						_root = cur->_left;
					}
					else
					{
						if(cur==parent->_left)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
						//需要找父节点,所以提前找好
						delete cur;
						cur=nullptr;//习惯
					}
				}
			else//两个孩子
			{
				//我们选择右子树的最小进行替换
				Node*find_min = cur->right;
				while(find_min->_left)
				{
					find_min = find_min->_left;
				}
				cur->_key = find_min->_key;//cur就是要替换的位置
				delte find_min;
				find_min=nullptr;//这个必须,不然是野指针
			}
			return true;
		}
		return false;
	}
}

②Find递归

public:
//...
bool FindR(const K&key)
{
	return _FindR(_root,key);
}
private:
bool  _FindR(Node*root,const K&key)
{
	if(root==nullptr) return false;
	if(root->val==key) return true;
	else if(root->_key<key)
		return _FindR(root->_right,key);
	else
		return _FindR(root->_left,key);
}

③Insert递归

public:
//...
bool InsertR(const K&key)
{
	return _InsertR(_root,key);
}
private:
bool  _InsertR(Node*root,const K&key)
{
	if(root==nullptr)
	{	
		root = new Node(key);//构造函数缺省左右nullptr
		return true;
	}
	if(root->_key<key)
		return InsertR(root->right,key);
	else if(root->_key>key)
		return InsertR(root->left,key);
	else return false;
}

④Erase递归,比Erase更简洁

public:
//...
bool EraseR(const K&key)
{
	return _EraseR(_root,key);
}
private:
bool  _EraseR(Node*root,const K&key)
{
	if(root==nullptr) return false;
	if(root->_key<key)
	{
		return _EraseR(root->_right,key);
	}
	else if(root->_key>key)
	{
		return _EraseR(root->_left,key);
	}
	else 
	{
		Node*del = root;//需要delete的结点
		if(root->_left == nullptr)
		{
			root=root->_right;//被取代
			delete del;
		}
		else if(root->_right ==nullptr)
		{
			root=root->left;
			delete del;//被子树取代
		}
		else
		{//两个孩子
			//用右子树最小来替换
			Node*find_mind=root->right;
			while(find_min->_left)
			{
				find-min=find_min ->_left;
			}
			swap(root->_key,find_min_key);
			//换到右子树的最后,然后再去Erase它就可以了
			_EraseR(_root->right,key);
		}
		return true;
	}
}

将要删的结点交换到右子树的最小值位置,再去delete

⑤析构函数

因为析构函数无法给参数,所以让析构函数调用Destory进行一个递归的删除

public:
~BSTree()
{
	Destory(_root);
}
private:
void Destory(Node*root)
{
	if(root==nullptr)
	{
		return;
	}
	Destory(root->left);
	Destory(root->right);
	delete root;
	//后序遍历来delete
}

⑥搜索二叉树的拷贝

二叉搜索树的构造需要用后序遍历来构造,需要保证根结点最后被构造才行

BSTree(const BSTree&bst)
{
	_root= _Copy(bst._root);
	//可以访问同类对象的私有成员
}
Node*_Copy(Node*root)
{
	if(root==nullptr)
	{
		return nullptr;
	}
	Node*copyRoot = new Node(root->_key);
	copyRoot->_left=_Copy(root->_left);
    copyRoot->_right=_Copy(root->_right);
    return copyRoot;//后序遍历
}

因为拷贝构造也是构造函数,拷贝构造只是构造函数的一种重载形式,所以,如果写了拷贝构造的话,编译器是不会默认生成默认构造的,需要自己去写。
或者呢,就要用一个关键字BSTree() = defualt;表示让编译器强制生成默认的构造函数

⑦赋值运算符重载

BSTree<K> &operator=(BSTree<K> bst)
{
	swap(bast._root,_root);
	return *this;
}

bst是传值传参,通过对拷贝构造的复用生成bst
然后此时只需要swap即可,因为我之前的旧树出作用域的时候会被自动析构,不用管

四、搜索二叉树存在的问题

搜索二叉树增删查的时间复杂度是O(h) h是树的高度
最坏的单支情况下是O(N),所以说搜索二叉树还是有缺陷的,最坏情况下增删查太慢了,想达到O(logN必须是满二叉树或者完全二叉树),所以就有了AVL树,红黑树等等,这些平衡树和搜索树的却别仅仅在效率上,功能上并没有区别

在这里插入图片描述

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

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

相关文章

unity学习笔记--day01

今天学习制作了一个简单的抽卡功能&#xff0c;学习结束后目录结构如下&#xff1a; .mate文件是unity生成的配置文件&#xff0c;不用管 制作第一张卡片 创建一个空物体&#xff0c;改名为Card。 在Card下挂载以下UI组件&#xff1a; 编写数据脚本并挂载&#xff0c;unity采用…

Nginx教程(4)—Keepalived

文章目录4.1 高可用集群架构Keepalived双机主备原理4.2 安装Keepalived4.3 Keepalived核心配置文件4.4 Keepalived实现双主机主备高可用测试4.5 高可用集群架构Keepalived双主热备原理Nginx教程一 Nginx教程二 Nginx教程三 4.1 高可用集群架构Keepalived双机主备原理 我们知道…

【计算机毕业设计】78.汽车租赁系统源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 目 录 摘 要 前 言 第1章 概述 1.1 研究背景 1.2 研究目的 1.3 研究内容 第二章 开发技术介绍 2.1 Java技术 2.2 Mysql数据库 2.3 B/S结构 2.4 SSM框架 第三章 系统分析 3.1 可行性分析 3.1.1 技术…

UnrealUBlueprintAsyncActionBase的使用

实现异步调用&#xff0c;之前我们介绍过一种FLatentActionInfo的方法&#xff0c;还有另外一种UBlueprintAsyncActionBase方法&#xff0c;可以实现异步节点&#xff0c;用于异步监听然后进行回调。按照如下步骤进行使用&#xff0c;我们同样以Delay一定帧数&#xff0c;并每帧…

面对新技术,必须找到与其发展相辅相成的长期主义的方法

从Meta股价的一路走低到扎克伯格发布的头显并不被用户买账&#xff0c;Facebook全力拥抱Meta正在经历一场过山车。   扎克伯格和他所带领下的Meta遭遇到的如此多的困境和难题&#xff0c;越来越多地让我们开始相信&#xff1a;所谓的元宇宙并非是一蹴而就的&#xff0c;它是一…

【云原生 Kubernetes】基于 Minikube 搭建第一个k8s集群

一、前言 对于k8s来说&#xff0c;搭建方式有多种&#xff0c;如果是生产环境&#xff0c;一般来说&#xff0c;至少需要3台节点确保服务的高可用性&#xff0c;常用的搭建方式列举如下&#xff08;提供参考&#xff09;&#xff1a; kubeadm搭建&#xff08;推荐&#xff09; …

postman测试环境的创建及发送请求方式

目录 一、创建工作环境 1、打开postman&#xff0c;点击工作区 2、点击新建 3、添加名字&#xff0c;点击创建 4、工作区可以自由切换工作区 5、点击创建发送请求 6、更换请求方式 7、保存测试 二、测试发送请求&#xff0c;使用的时候服务一定要启动 1、普通传参&…

C++ 类型转换

目录 C语言中的类型转换 为什么C需要四种类型转换 C&#xff1a;命名的强制类型转换 static_cast reinterpret_cast const_cast dynamic_cast C语言中的类型转换 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&#xff0c…

信息学奥赛一本通——1163:阿克曼(Ackmann)函数

文章目录1163&#xff1a;阿克曼(Ackmann)函数【题目描述】【输入】【输出】【输入样例】【输出样例】分析代码1163&#xff1a;阿克曼(Ackmann)函数 时间限制:1000ms内存限制:65536KB提交数:24804通过数:20247时间限制: 1000 ms 内存限制: 65536 KB 提交数: 24804 通过数: 202…

第三十章 linux-模块的文件格式与EXPORT_SYMBOL的实现

第三十章 linux-模块的文件格式与EXPORT_SYMBOL的实现 文章目录第三十章 linux-模块的文件格式与EXPORT_SYMBOL的实现模块的文件格式EXPORT_SYMBOL的实现模块的文件格式 以内核模块形式存在的驱动程序&#xff0c;比如demodev.ko&#xff0c;其在文件的数据组织形式上是ELF&am…

数据结构---快速排序

快速排序分治法思想基准元素的选择元素交换双边循环法JAVA实现单边循环法JAVA实现快速排序也是从冒泡排序演化而来使用了 分治法&#xff08;快的原因&#xff09;快速排序和冒泡排序共同点&#xff1a;通过元素之间的比较和交换位置来达到排序的目的。 快速排序和冒泡排序不同…

JavaWeb核心:HTTPTomcatServlet

HTTP 概念: Hyper Text Transfer Protocol&#xff0c;超文本传输协议&#xff0c;规定了浏览器和服务器之间数据传输的规则。 HTTP-请求数据格式 HTTP-响应数据格式 响应状态码的大的分类 常见的响应状态码 Tomcat 简介 概念: Tomcat是Apache 软件基金会一个核心项目&#…

【云原生】Prometheus 自定义告警规则

文章目录一、概述二、告警实现流程三、告警规则1&#xff09;告警规则配置1&#xff09;监控服务器是否在线3&#xff09;告警数据的状态四、实战操作1&#xff09;下载 node_exporter2&#xff09;启动 node_exporter3&#xff09;配置Prometheus加载node_exporter4&#xff0…

这样也可以让图像正向扩散

🍿*★,*:.☆欢迎您/$:*.★* 🍿 怎样的扩散取决于b是不是随机噪声 是随机噪声 则是扩散模型 如stable diffision 如果是非噪声则是方向模型 方向模型是指 在已知几个连续的输入 后可以通过模型的辅助预测扩散的方向 而 stable diffision 是通过预测反扩散方向 本质就…

VS2017中OpenCV编程插件Image Watch安装和使用介绍

安装 下载适合vs2017最新版本的Image Watch(ImageWatch.vsix)&#xff0c;下载地址 安装ImageWatch&#xff0c;双击ImageWatch.vsix进行安装即可&#xff1b; 使用 打开一个OpenCV工程&#xff0c;在Debug下设置断点&#xff0c;通过view -> other windows -> Image W…

基于51单片机宠物自动投料喂食器控制系统仿真设计( proteus仿真+程序+讲解视频)

基于51单片机宠物自动投料喂食器控制系统仿真设计( proteus仿真程序讲解视频&#xff09; 仿真图proteus 7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0029 视频讲解 基于51单片机的宠物自动投料喂食器控制系统proteu…

数据结构—最小生成树

目录 一、生成树 二、最小生成树&#xff08;代价最小树&#xff09; 三、求最小生成树 1、Prim算法&#xff08;普里姆&#xff09; 2.Kruskal 算法&#xff08;克鲁斯卡尔&#xff09; 3.Prim算法和Kruskal算法对比 一、生成树 连通图的生成树是包含图中全部顶点的一个…

[附源码]Nodejs计算机毕业设计基于框架的秧苗以及农产品交易网站Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

算法分析专业工具——大O记法

本文内容借鉴一本我非常喜欢的书——《数据结构与算法图解》。学习之余&#xff0c;我决定把这本书精彩的部分摘录出来与大家分享。 写在前面 从之前的章节中我们了解到&#xff0c;影响算法性能的主要因素是其所需的步数。 然而&#xff0c;我们不能简单地把一个算法记为“…

Postman下载,安装,汉化,注册及登录教程

目录 一、Postman简介 二、Postman的注册 1、首先下载Postman&#xff0c;进入官网&#xff1a;Download Postman | Get Started for Free 2、安装Postman 3、下载汉化包 4、找到所下载的app.zip文件&#xff0c;将文件进行解压&#xff0c;放置到此路径下 Postman\app9…