【C++课程学习】:二叉搜索树

news2024/11/24 16:12:01

🎁个人主页:我们的五年

🔍系列专栏:C++课程学习

🎉欢迎大家点赞👍评论📝收藏⭐文章

目录

二叉树搜索树的概念:

节点的结构:

⚽️结构:

⚽️ 构造函数:

搜索二叉树的查找:

⛳️查找步骤:

⛳️时间复杂度:

⛳️代码实现:

搜索二叉树的插入:

🌴插入步骤:

🌴插入代码:

二叉树的删除:

🍁删除步骤:

●叶子节点(左右指针都为空):

●只有一个孩子(左子树为空,或者右子树为空):

●有两个孩子:

🍁实现代码:

拷贝构造,析构函数:

搜索二叉树的应用:


 

二叉树搜索树的概念:

 二叉搜索树也叫二叉排序树二叉查找树

二叉搜索树可以为空,但是不为空的时候,具有下面的性质

●非空左子树的所有键值小于根的键值。

●非空右子树的所有键值大于根的键值。

●左右子树任然是搜索二叉树。

节点的结构:

⚽️结构:

因为搜索二叉树也是二叉树,要定义左右两个节点指针。此时先以K树讲解。此时的节点结构为:

⚽️ 构造函数:

在实践情况中,我们一般用一个T类型的值(键值)去进行构造一个节点。其他的用BST_node去进行拷贝构造基本是不可能的。所以写这一个构造函数就够了。

struct BST_Node {
	//用key值进行构造
	BST_Node(const T& key=T())
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
	{

	}
	//左右节点指针,以及键值
	BST_Node<T>* _left;
	BST_Node<T>* _right;
	T _key;
};

另外下面还有对该节点和节点指针重命名的。 

    typedef BST_Node<T> node;
    typedef node* pnode;

搜索二叉树的查找:

⛳️查找步骤:

如果要查找一个值,根据二插树的性质。从根节点开始,如果根的键值不是,那么如果要查找的键值大于根,就往右子树走。如果小于根的键值,那么就往左子树走。如果走到空了,还没找到,那么这个值就不存在。

⛳️时间复杂度:

最坏情况是查找树的高度次。

但是此时不是满二叉树,不能认为现在的二叉树的高度为(logN)+1。

最坏二叉树的高度为N,所以查找就是N次。时间复杂度就是O(N)。

⛳️代码实现:

	bool find(T& key)
	{
		pnode p=_root;
		while (p)
		{
			if (key < _root->_key)
				p = p->_left;
			else if (key > _root->_key)
				p = p->_right;
			else
				return true;
		}
		return false;
	}

搜索二叉树的插入:

🌴插入步骤:

根据搜索二叉树的规则,如果要插入的值小于此时的键值,那么就往左边走,如果大于此时的键值就往右走。直到走到空为止,然后用一个键值为key的新节点插入到搜索二叉树中。要插入,就要知道父节点,所以在走的过程中,要用parent_cur时刻记录cur的父节点。

因为当_root为空时进行了特判,所以parent_cur不可能为nullptr,所以不会发生对野指针的解引用。

🌴插入代码:

	bool insert(const T& key)
	{
		//当根节点为nullptr时,直接向_root插入节点
		if (_root == nullptr)
		{
			_root = new node(key);
			return true;
		}
		//_root为二叉搜索树的根节点
		pnode cur = _root;
		pnode parent_cur = nullptr;
		while (cur)
		{
			//如果要插入的值小于此时的根节点,就往左边走
			if (key < cur->_key)
			{
				parent_cur = cur;
				cur = cur->_left;
			}

			//如果要插入的值大于此时的根节点,就往右边走
			else if (key > cur->_key)
			{
				parent_cur = cur;
				cur = cur->_right;
			}

			//此时表示二叉树中存在该值,就返回false
			else
				return false;
		}

		//申请节点,cur在parent_cur的左边就把新节点插入parent_cur的左边,如果不是就插入右边
		pnode newnode = new node(key);
		if (key< parent_cur->_key)
			parent_cur->_left = newnode;
		else
			parent_cur->_right = newnode;
		return true;
	}

二叉树的删除:

🍁删除步骤:

把搜索二叉树的节点进行分类,具体点可以分为三种情况:

●叶子节点(左右指针都为空):

删除叶子节点时,直接删除即可,如果叶子节点在父节点的左边,就把父节点的左指针变为空,如果叶子节点在父节点的右边,就把父节点的右指针变为nullptr。

注意:如果此时叶子节点为_root(根节点),就没有父节点,只需把_root变为nullptr。

只有一个孩子(左子树为空,或者右子树为空):

要删除这样的节点也是比较简单的,只需要把该节点的孩子给父节点就可以。叶子节点也可以当成这种情况进行处理。

同样也应该注意该节点是不是根(_root)节点。

●有两个孩子:

这种情况,就不能直接把两个孩子都给父亲,因为一个节点最多有两个孩子,如果父节点已经有一个孩子了,就不能把要删除的节点两个孩子给父节点了。

所以我们就需要去找一个节点来带这两个孩子。要找的这个节点要有这样的性质:

●如果删除的节点在父节点左边,那么找到的新节点就要比父节点小。相反就比父节点大。

解决办法:

就在要删除的这棵树中找,就满足这样的性质。

下面图中在绿色这棵树中找,全部满足键值大于根节点5。

●新的节点必须比左树所有节点都大比右树都小

解决办法:

1.左树的节点都比根的键值小,那就比所有右树节点小。左树所有节点都满足了比右树都小。

2.在左树中找到最大就满足了左树节点都小于这个节点。从左树开始,一直往右边走,就可以满足这三个性质。

上图的键值为7的节点。

🍁实现代码:

	bool erase(const T& key)
	{
		pnode parent_cur = nullptr;
		pnode cur = _root;

		//寻找键值为key的节点
		while (cur)
		{
			if (key < cur->_key)
			{
				parent_cur = cur;
				cur = cur->_left;
			}

			else if (key > cur->_key)
			{
				parent_cur = cur;
				cur = cur->_right;
			}
			else
				break;	//找到了
		}
		if(cur==nullptr)
			return false;
		//只有右孩子,叶子节点可以当成这种情况处理
		if (cur->_left == nullptr)
		{
			if (cur == _root)
			{
				_root = cur->_right;
			}
			else
			{
				if (parent_cur->_left == cur)
					parent_cur->_left = cur->_right;
				else
					parent_cur->_right = cur->_right;
			}
			delete cur;
			return true;
		}
		//只有左孩子
		else if (cur->_right == nullptr)
		{
			if (cur == _root)
			{
				_root = cur->_left;
			}
			else
			{
				if (parent_cur->_left == cur)
					parent_cur->_left = cur->_left;
				else
					parent_cur->_right = cur->_left;
			}
			delete cur;
			return true;
		}
		//有两个孩子
		else
		{
			pnode left_max_parent = cur;
			pnode left_max = cur->_right;
			while (left_max->_right)
			{
				left_max_parent = left_max;
				left_max = left_max->_right;
			}
			cur->_key = left_max->_key;

			if (left_max == left_max_parent->_left)
				left_max_parent->_left=left_max->_left;
			else
				 left_max_parent->_right=left_max->_left;
			delete left_max;
			return true;
		}
	}

拷贝构造,析构函数:

进行深拷贝,从_root开始遍历,进行深拷贝。

析构函数也要进行逐一释放。

	BST(const BST<T>& t)
	{
		_root = copy(t._root);
	}
	pnode copy(pnode root)
    {
		if (root == nullptr)
			return root;
		pnode newnode = new node;
		newnode->_key = root->_key;
		newnode->_left = copy(root->_left);
		newnode->_right = copy(root->_right);
		return newnode;
	}
	~BST()
	{
		Destroy(_root);
	}
	void Destroy(pnode root)
	{
		if (root == nullptr)
			return;
		Destroy(root->_left);
		Destroy(root->_right);
		delete root;
	}

搜索二叉树的应用:

K模型:

上面所说的是K模型,在插入一些数以后,可以去查找某个值在不在这棵树中。例如:查找一个单词是否正确,就可以去一棵有所以单词的搜索二叉树中寻找在不在树中。

KV模型:

就是一个Key值,会与一个value值对应,找到了key值,就可以得到value值。

例如:英汉字典,每个单词就可以对应一个中文意思,找到了key(英文)就可以得到value(中文)。


这种二叉树有极端情况:

使得它的时间复杂度为O(N)。

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

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

相关文章

Axure是什么软件?全方位解读助力设计入门

在产品设计和开发领域&#xff0c;Axure是一款大名鼎鼎且功能强大的软件&#xff0c;它为专业人士和团队提供了卓越的设计支持&#xff0c;帮助他们将创意转化为实际可操作的产品原型。 一、Axure 的基本介绍 Axure是一款专业的原型设计工具&#xff0c;主要用于创建交互式的…

java里面使用groovy案例+详解

场景&#xff1a; 最近有一个计算商品运费的&#xff0c;如果商品的数量大于快递公司设置的数量 10 那么超出部分也需要计算额外运费&#xff0c;那么这些计算过程代码我能不能不在java里面写呢&#xff0c;用一种可配置化的方式来根据不同的传参计算出运费&#xff1f; 页面传…

单体架构 IM 系统之核心业务功能实现

在上一篇技术短文&#xff08;单体架构的 IM 系统设计&#xff09;中&#xff0c;我们讨论了在 “用户规模小、开发人员少、开发时间短” 的业务背景下&#xff0c;采取 “怎么简单怎么做&#xff0c;怎么快怎么来” 的研发策略&#xff0c;于是设计了 单体架构的IM系统&#x…

Linux部署nginx访问文件403

问题描述&#xff1a;在linux服务器上通过nginx部署&#xff0c;访问文件403 新配置了一个用户来部署服务&#xff0c;将部署文件更新到原有目录下&#xff0c;结果nginx访问403 原因&#xff1a;没有配置文件的读写权限&#xff0c;默认不可读写&#xff0c;nginx无法访问到文…

解决 C/C++ 中 “invalid use of incomplete type” 编译错误

解决 C/C++ 中 “invalid use of incomplete type” 编译错误 一、错误原因二、常见场景三、解决方法四、最佳实践五、总结在 C 和 C++ 编程中,invalid use of incomplete type 错误通常发生在尝试使用一个未完全定义的类型时。这个错误表明编译器在当前上下文中没有足够的信息…

使用 Python 实现高效网页爬虫——从获取链接到数据保存

前言 在这个时代,网络爬虫已成为数据分析与信息收集不可或缺的技术之一。本文将通过一个具体的Python项目来介绍如何构建一个简单的网络爬虫,它能够自动抓取指定网站的文章链接、标题、正文内容以及图片链接,并将这些信息保存为CSV文件。 目标网站 一、准备工作 在开始编…

C# 有趣的小程序—桌面精灵详细讲解

C# 桌面精灵详细讲解 最近写了一个简化版桌面精灵&#xff0c;效果如图所示&#xff0c;可以实现切换动画&#xff0c;说话、鼠标拖动&#xff0c;等功能。具体如何做&#xff0c;我发布了一个资源里面包含ppt详解、源代码以及动画素材。放心吧&#xff0c;免费的&#xff0c;…

微软日志丢失事件敲响安全警钟

NEWS | 事件回顾 最近&#xff0c;全球最大的软件公司之一——微软&#xff0c;遭遇了一场罕见的日志丢失危机。据报告&#xff0c;从9月2日至9月19日&#xff0c;持续长达两周的时间里&#xff0c;微软的多项核心云服务&#xff0c;包括身份验证平台Microsoft Entra、安全信息…

Mysql ERROR 1451 (23000) 外键处理异常

通过临时设置外键失效&#xff0c;来规避报错 第一步 # 临时设置外键失效 SET FOREIGN_KEY_CHECKS 0; 第二步&#xff1a;执行更新或者删除操作 第三步&#xff1a; # 操作结束后恢复外键 SET FOREIGN_KEY_CHECKS 1;

智慧社区可视化解决方案:科技引领社区服务与管理新篇章

随着社会的发展&#xff0c;智慧社区作为新型城镇化发展目标和社区服务体系建设的重要举措&#xff0c;正逐步改变着我们的生活方式。智慧社区通过综合运用现代科学技术&#xff0c;整合区域资源&#xff0c;提升社区治理和服务水平&#xff0c;为居民提供更为便捷、高效、安全…

基于redis实现API接口访问次数限制

一&#xff0c;概述 日常开发中会有一个常见的需求&#xff0c;需要限制接口在单位时间内的访问次数&#xff0c;比如说某个免费的接口限制单个IP一分钟内只能访问5次。该怎么实现呢&#xff0c;通常大家都会想到用redis&#xff0c;确实通过redis可以实现这个功能&#xff0c…

【go从零单排】Ticker

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 语言中&#xff0c;Ticker 是一个用于定期执行某些操作的工具。它属于 tim…

C++《stack与queue》

在之前的章节我们学习了C当中string、vector和list三种容器并且试着模拟实现这三种容器&#xff0c;那么接下来在本篇当中我们将STL当中的stack和queue&#xff0c;并且在学习stack和queue的使用之后和之前一样还会试着模拟实现stck和queue。由于stck和queue的模拟实现较为简单…

网页web无插件播放器EasyPlayer.js点播播放器遇到视频地址播放不了的现象及措施

在数字媒体时代&#xff0c;视频点播已成为用户获取信息和娱乐的重要方式。EasyPlayer.js作为一款流行的点播播放器&#xff0c;以其强大的功能和易用性受到广泛欢迎。然而&#xff0c;在使用过程中&#xff0c;用户可能会遇到视频地址无法播放的问题&#xff0c;这不仅影响用户…

【前端】HTML标签汇总

目录 展示用户信息的标签 1.文本标签 span 2.标题标签 h1~h6 3.竖着布局的标签 div 4.段落标签 p 5.超链接标签 a 5.1跳转至网上的资源 5.2锚点 6.列表标签 6.1有序列表 ol 6.2无序列表 ul 7.图片标签 img 7.1相对路径 7.1.1兄弟关系 7.1.2叔侄关系 7.1.3表兄弟…

xtu oj 加一

样例输入# 2 4 1 2 3 4 4 3 2 4 1样例输出# 3 5 解题思路&#xff1a;最小操作次数一定是把所有数变成数组中最大值max。 1、找最大值&#xff0c;一开始我把max初始值设为0&#xff0c;如果a[i]>max,maxa[i],WA了。又看了一遍题目&#xff0c;发现所有整数的绝对值小于…

Windows10/11开启卓越性能模式 windows开启卓越性能电源模式 工作电脑开启卓越性能模式 电脑开启性能模式

Windows10/11开启卓越性能模式 windows开启卓越性能电源模式 工作电脑开启卓越性能模式 电脑开启性能模式 1、所要用到的激活工具2、开启电脑卓越性能模式Windows11Windows10在电源模式中选择卓越性能模式 3、将系统版本切换为 工作站版本 1、所要用到的激活工具 KMS激活工具(…

人工智能、机器学习与深度学习:层层递进的技术解读

引言 在当今科技快速发展的时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为一个热门话题&#xff0c;几乎渗透到了我们生活的方方面面。从智能手机的语音助手&#xff0c;到自动驾驶汽车&#xff0c;再到医疗诊断中的图像识别&#xff0c;人工智能的应用正在改变我…

光流法(Optical Flow)

一、简介 光流法&#xff08;Optical Flow&#xff09;是一种用于检测图像序列中像素运动的计算机视觉技术。其基于以下假设&#xff1a; 1.亮度恒定性假设&#xff1a;物体在运动过程中&#xff0c;其像素值在不同帧中保持不变。 2.空间和时间上的连续性&#xff1a;相邻像素之…

OkHttp网络请求框架

添加依赖 在 build.gradle 文件中添加 OkHttp 依赖&#xff1a; dependencies {implementation("com.squareup.okhttp3:okhttp:4.10.0") }使用OkHttp发起GET请求 同步请求 public class MainActivity extends AppCompatActivity {// Used to load the okhttptes…