C++进阶之二叉搜索树

news2024/10/6 18:34:33

个人主页:点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶     C++进阶​    ​​​​算法

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

目录

一.二叉搜索树概念

二.实现

2.1插入

2.2遍历

2.3查找

2.4删除

2.4.1删除节点的左子树为空

2.4.2删除节点的右子树为空

2.4.3删除节点的左子树和右子树都不为空

        ​编辑2.4.4代码

三.K-V模型

 四.二叉搜索树的性能分析


一.二叉搜索树概念

        二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:若它的左子树不为空,则左子树上所有节点的值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树。

二.实现

2.1插入

        插入遵循二叉树的规则,左子树都比父节点小,右子树都比父节点大,我们可以看下面图片:

我们的代码如下:

bool insert(const K &key)
{
	Node* newnode = new Node(key);
	if (_root == nullptr) _root = newnode;
	else
	{
		Node* cur = _root, *parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (key < cur->_key) cur = cur->_left;
			else if (key > cur->_key) cur = cur->_right;
			else  return false;
			
		}
		if (key < parent->_key) parent->_left = newnode;
		else parent->_right = newnode;
	}
	return true;
}

先判断时不是根节点,然后再根据二叉搜索树的规则进行插入。

2.2遍历

        我们遍历就是二叉树的中序遍历,这样遍历就是天然有序的从小到大进行排序的数据,我们看代码:

public:
	void InOrder()
	{
		_InOrder(_root);
	}
private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

	    _InOrder(root->_left);
	    cout << root->_key << " ";
	    _InOrder(root->_right);
    }

        这里为什么会选择让函数在private里和public里呢?主要就是我们需要使用_root这个成员变量,我们可以使用缺省 ,但是会报错,我们想要使用成员变量我们就可以将函数封装在privae里面,然后调用就可以了。

2.3查找

        二叉搜索树的查找和插入类似,我们查找某一个值就相当于插入某一个值,根据插入规则就可以找到某一个值,我们看下面图片:

我们看代码:

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;
}

2.4删除

        在这里我们的删除分为:删除节点的左子树为空,删除节点的右子树为空,删除节点的左子树和右子树都不为空这三种情况(删除节点的左子树和右子树都为空在删除节点的左子树为空情况中)。

2.4.1删除节点的左子树为空

        分为删除节点为根节点和删除节点不为根节点,我们看下面动图:

2.4.2删除节点的右子树为空

        分为删除节点为根节点和删除节点不为根节点,我们看下面动图:

2.4.3删除节点的左子树和右子树都不为空

        2.4.4代码

 

	bool Erase(const K& key)
	{
		Node* cur = _root, * parent = nullptr;
 		if (_root == nullptr) return false;
		while (cur)
		{

			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 (parent->_left == cur) parent->_left = cur->_right;
						else parent->_right = cur->_right;
					}
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					if (cur == _root) _root = cur->_left;
					else 
					{
						if (parent->_left == cur) parent->_left = cur->_left;
						else parent->_right = cur->_left;
					}
					delete cur;
				}
				else
				{
					Node* RightMin = cur->_right;
					Node* PRightMin = cur;
					while (RightMin->_left )
					{
						PRightMin = RightMin;
						RightMin = RightMin->_left;
					}

					swap(RightMin->_key, cur->_key);

					if(PRightMin->_left ==RightMin) PRightMin->_left = RightMin->_right ;
					else PRightMin->_right = RightMin->_right;

					delete RightMin;
				}
				return true;
			}

		}
		return false;
	}

三.K-V模型

        K—V模型和上面的代码类似,只是多一个V值,下面是代码这里不做具体分析

template<class K,class V>
struct BSTreeNode
{
	typedef BSTreeNode<K,V> Node;
	Node* _left;
	Node* _right;
	K _key;
	V _val;
	BSTreeNode(const K& key,const V&val)
		:_left(nullptr)
		, _right(nullptr)
		,_key(key)
		, _val(val)
	{}
};
template<class K,class V>
class BSTree
{
public:
	typedef BSTreeNode<K,V> Node;
	//中序遍历
	void INOrder()
	{
		_INOrder(_root);
		cout << endl;
	}
	//插入
	bool insert(const K& key , const V&val)
	{
		Node* newnode = new Node(key,val);
		if (_root == nullptr)
		{
			_root = newnode;
			return true;
		}

		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_key < val)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > val)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				return false;
			}
		}
		if (val > parent->_val)
		{
			parent->_right = newnode;
		}
		else
		{
			parent->_left = newnode;
		}
		return true;
	}
	//查找
	Node* find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key < key)
			{
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		return nullptr;
	}
	//删除
	bool erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				if (cur->_left == nullptr)
				{
					if (_root == cur)
					{
						_root = cur->_right;
					}
					if (parent->_left == cur) parent->_left = cur->_right;
					else parent->_right = cur->_right;
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					if (_root == cur)
					{
						_root = cur->_left;
					}
					if (parent->_left == cur) parent->_left = cur->_left;
					else parent->_right = cur->_left;
					delete cur;
				}
				else
				{
					//找到左子树的最大值或者右子树的最小值,进行替换
					//Node* LessNodeParent = nullptr;
					Node* LessNodeParent = cur;
					Node* LessNode = cur->_right;
					while (LessNode->_left)
					{
						LessNodeParent = LessNode;
						LessNode = LessNode->_left;
					}
					swap(cur->_key, LessNode->_key);
					swap(cur->_val, LessNode->_val);
					if (LessNodeParent->_left == LessNode) LessNodeParent->_left = LessNode->_right;
					else LessNodeParent->_right = LessNode->_right;
					delete LessNode;
				}
				return true;
			}
		}
		return false;
	}
private:
	void _INOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_INOrder(root->_left);
		cout << root->_val << " ";
		_INOrder(root->_right);
	}
	Node* _root = nullptr;
};

 四.二叉搜索树的性能分析

        插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

 

最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:log_2 N
最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为:N

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

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

相关文章

K8s存储对象的使用

背景和概念 容器中的文件在磁盘上是临时存放的&#xff0c;这给在容器中运行较重要的应用带来一些问题&#xff1a; 当容器崩溃或停止时&#xff0c;此时容器状态未保存&#xff0c; 因此在容器生命周期内创建或修改的所有文件都将丢失。另外 在崩溃期间&#xff0c;kubelet 会…

3D打印随形水路:模具水路的革命性技术

在快速发展的模具制造行业中&#xff0c;3D打印技术以其独特的优势正在引领一场技术革命。其中&#xff0c;3D打印随形水路技术&#xff0c;凭借其灵活性和定制化设计的能力&#xff0c;为模具带来了前所未有的变革。 模具3D打印随形水路技术&#xff0c;是一种利用3D打印技术制…

《帝国时代 III:决定版》秘籍 怎么在苹果电脑上玩《帝国时代 III:决定版》

《帝国时代 III&#xff1a;决定版》是一款让玩家沉浸于历史长河体验从大航海时代到工业革命时期的游戏。下面我们来看看《帝国时代 III&#xff1a;决定版》是什么类型的游戏&#xff0c;《帝国时代 III&#xff1a;决定版》Mac安装教程的相关内容。 一、《帝国时代 III&…

UI设计公司-蓝蓝设计-交通行业ui设计解决方案

来百度APP畅享高清图片 这是北京兰亭妙微科技有限公司&#xff08;简称蓝蓝设计&#xff09;在交通行业的一些ui设计经验&#xff0c;我们建立了UI设计分享群&#xff0c;每天会分享国内外的一些优秀设计&#xff0c;如果有兴趣的话&#xff0c;可以进入一起成长学习&#xff0…

流量录制学习

AREX Cloud | AREX (arextest.com) 流量录制学习&#xff0c;比vivo的moonbox要好用

FineReport使用小记(不断更新中…………)

FineReport使用小记 1. 单元格相关设置1.1. 单元格值样式 2. 报表块设置2.1. 给报表块加单位 1. 单元格相关设置 1.1. 单元格值样式 1. 百分比样式 选中单元格&#xff0c;单元格属性——>文本——>格式——>百分比 下面可以选择保留几位小数&#xff0c;图中为保留…

测试用例如何编写?史上最全接口测试-用例编写设计总结(测试点)

前言 接口测试的流程 接口测试也是属于功能测试&#xff0c;所以跟我们以往的功能测试流程并没有太大区别&#xff0c;测试流程依旧是&#xff1a; 1、测试接口文档&#xff08;需求文档&#xff09; 2、根据接口文档编写测试用例&#xff08;用例编写完全可以按照以往规则来…

查询SQL:文章浏览1

问题描述 请查询出所有浏览过自己文章的作者 结果按照 id 升序排列。 查询结果的格式如下所示&#xff1a; 题目分析&#xff1a; 这题主要考察排序asc&#xff08;升序&#xff09;、desc&#xff08;降序&#xff09;以及distinct字段。 解决方案&#xff1a; select DIS…

033.搜索旋转排序数组

题意 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给方法之前&#xff0c;nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了旋转&#xff0c;使数组变为 [nums[k], nums[k1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]&…

【Python系列】Python 中的运算符:基础与高级用法

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

1898java疫情防控管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java 疫情防控管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发…

使用LabVIEW进行大数据数组操作的优化方法

针对大数据量数组操作&#xff0c;传统的内存处理方法可能导致内存不足。通过LabVIEW的图像批处理技术&#xff0c;可以有效地进行大数据数组操作&#xff0c;包括分块处理、并行处理和内存优化等。这种方法能显著提高处理效率和系统稳定性。 图像批处理的优势 内存优化&#…

navi_cat查看数据库的连接密码

Navi_Cat 建立连接&#xff0c;来访问数据库。可惜&#xff0c;忘记了数据库密码&#xff0c;没事&#xff0c;这么搞。 首先先导出链接&#xff0c;再从链接里取出被加密的密码&#xff0c;然后找个可在线运行PHP的网站&#xff08;代码在线运行 - 在线工具&#xff09;&…

ROS云课三分钟外传之CoppeliaSim_Edu_V4_1_0_Ubuntu16_04

三分钟热度试一试吧&#xff0c;走过路过不要错过。 参考之前&#xff1a; 从云课五分钟到一分钟之v-rep_pro_edu_v3_6_2-CSDN博客 git clone https://gitcode.net/ZhangRelay/v-rep_pro_edu_v3_6_2_ubuntu16_04.gittar -xf v-rep_pro_edu_v3_6_2_ubuntu16_04/V-REP_PRO_EDU…

Python爬取城市空气质量数据

Python爬取城市空气质量数据 一、思路分析1、寻找数据接口2、发送请求3、解析数据4、保存数据二、完整代码一、思路分析 目标数据所在的网站是天气后报网站,网址为:www.tianqihoubao.com,需要采集武汉市近十年每天的空气质量数据。先看一下爬取后的数据情况: 1、寻找数据…

网络空间安全数学基础·多项式环与有限域

5.1 多项式环&#xff08;掌握&#xff09; 5.2 多项式剩余类环&#xff08;理解&#xff09; 5.3 有限域&#xff08;熟练&#xff09; 5.1 多项式环 定义&#xff1a;设F是一个域&#xff0c;称是F上的一元多项式&#xff0e; 首项&#xff1a;如果an≠0&#xff0c;则称 a…

618数码产品有什么推荐?四大2024“宝藏”数码产品推荐!

随着618购物节的热情逐渐升温&#xff0c;你是否在繁多且诱人的商品海洋中迷失方向&#xff0c;难以找到那最心仪的宝贝&#xff1f;团团在此特别为你精心挑选了一系列经过亲身体验的优质好物。这些推荐不仅时尚前沿&#xff0c;更贴合你的日常生活需求&#xff0c;确保实用与品…

A6500-LC LVDT 前置器,用于A6500-UM, 导轨安装

电源 22.5V to 32VDC <30mA <0.1%/V <60V( 使用SELV/PELV 供电电源) 约2.2Vrms,5kHz IP20 IEC 60529 -35C to 75C(-31F to 167F) -35C to 85C(-31F to 185F) 电流损耗 供电电压对 运行温度 存储温度 0.35mm(0.014 in ),10 to 55Hz 15g 根据 EN 60068-2-27 根据IEC 613…

Ubuntu server 24 (Linux) sudo 免输密码

1 sudo 使用要输入密码&#xff0c;费时费力。 2 sudo命令免输密码&#xff0c;需要修改/etc/sudoers文件 #本文以test用户为例,#允许不需要输入密码执行 sudo vi /etc/sudoers test ALL(ALL) NOPASSWD: ALL %sudo ALL(ALL:ALL) ALL --> #%sudo ALL(ALL:ALL) ALL#所有…

数据中心网络架构设计与优化

数据中心是现代企业和组织的核心基础设施&#xff0c;它们用于存储、处理和传输大量的数据和信息。为了满足不断增长的数据需求和提供可靠的服务&#xff0c;设计和优化数据中心网络架构至关重要。 首先&#xff0c;数据中心网络架构设计需要考虑可扩展性。随着业务的增长&…