C++进阶 二叉搜索树

news2024/11/15 23:04:53

 目录

二叉搜索树概念

二叉搜索树的模拟实现

二叉搜索树的查找

二叉搜索树的插入

二叉搜索树的删除

二叉搜索树的性能分析

二叉搜索树的应用

K模型

 KV模型


二叉搜索树概念

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

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

可以看到二叉搜索树通过中序遍历后得出的数组是有序的。 


二叉搜索树的模拟实现

首先我们要创建一个节点结构体,结构体内容要包括指向左右节点的指针和自身的键值,为了能适配int的内置类型和string的自定义类型,我们使用模板构建节点结构体。

template<class K>
struct BSTNode
{
	K _key;
	BSTNode<K>* _left;
	BSTNode<K>* _right;

	BSTNode(const K& key)
		:_key(key)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

以下操作我们用以下数组进行操作:

int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};

  我们先搭一个二叉搜索树的基本框架,以节点为类型构建一个根节点root:

template<class K>
class BSTree
{
	typedef BSTNode<K> Node;

private:
	Node* _root = nullptr;
};

二叉搜索树的查找

要实现查找功能要满足以下两个条件:

  1. 从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
  2. 最多查找高度次,走到到空,还没找到,这个值不存在。

二叉搜索树查找的模拟实现代码如下: 

	bool 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 true;  //找到了
			}
		}
		return false;  //没找到
	}

二叉搜索树的插入

插入的具体过程如下:

  1. 树为空,则直接新增节点,赋值给root指针
  2. 树不空,按二叉搜索树性质(比根大插右边,比根小插左边)查找插入位置,插入新节点

 二叉搜索树插入的模拟实现代码如下: 

	bool Insert(const K& key)
	{
		if (_root == nullptr) //树为空,当前节点就是根节点
		{
			_root = new Node(key);
			return true;
		}
		Node* parent = nullptr; //记录要插入位置的上一个节点(根节点)
		Node* cur = _root;
		while (cur) //找插入位置
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else //相等说明插不进去了(不符合二叉搜索树的性质)
			{
				return false;
			}
		}
		cur = new Node(key);  //创建一个新节点
		if (parent->_key < key)  //链接节点
		{
			parent->_right = cur;
		}
		else
		{
			parent->_left = cur;
		}
		return true;
	}

这里为什么用bool类型作为返回值?原因:要插入的值可能和根节点相等,如果相等就不能插入,因为违反了二叉搜索树的性质(比根大插右边,比根小插左边)。


二叉搜索树的删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情 况:

  1. 要删除的结点无孩子结点
  2. 要删除的结点只有左孩子结点
  3. 要删除的结点只有右孩子结点
  4. 要删除的结点有左、右孩子结点

看起来有待删除节点有4中情况,实际情况1可以与情况2或者3合并起来,因此真正的删除过程如下:

  1. 情况1:没有孩子——直接删除
  2. 情况2:一个孩子——按照二叉搜索树性质,将其子节点连接到父节点上
  3. 情况3:两个孩子——在它的右子树中寻找中序下的第一个结点(key最小),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除  

此为删除的是根节点且根节点左子树为空的情况,直接将右子树的地址赋值给root,让他作为根节点即可,当然根节点右子树为空也是同样操作,直接赋值。 

 注意这里不会出现大小混乱,原因:

如果删除的节点是父节点的右子树,比父亲大,他的右子树比他本身还要大,所以接上后成立

如果删除的节点是父节点的左子树,比父亲小,根据性质,左子树所有值都比根小,所以删除节点的右子树也比父节点小,所以成立。

 这里的替代法找右子树的最小节点(最左节点)或者左子树的最大节点(最右节点都可以)

删除的模拟实现代码如下:

	bool Erase(const K& key)
	{
		Node* parent = nullptr;  //记录要删除位置的上一个节点
		Node* cur = _root;
		while (cur) // 找要删除的节点
		{
			if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				// 删除
				// 0-1个孩子的情况
				if (cur->_left == nullptr)  //左孩子为空
				{
					if (parent == nullptr)   // 删除根节点且左子树为空
					{
						_root = cur->_right;
					}
					else  //删除的不是根节点
					{
						if (parent->_left == cur)   //看删除的节点是父节点的左还是右
							parent->_left = cur->_right;  //是左就把右子树接左边
						else
							parent->_right = cur->_right;  //右就把右子树接右边
					}
					delete cur;  //避免野指针
					return true;
				}
				else if (cur->_right == nullptr)  //右孩子为空
				{
					if (parent == nullptr)
					{
						_root = cur->_left;
					}
					else
					{
						if (parent->_left == cur)
							parent->_left = cur->_left;
						else
							parent->_right = cur->_left;
					}

					delete cur;  
					return true;
				}
				else
				{
					// 2个孩子的情况
					// 右子树的最小节点作为替代节点
					Node* rightMinP = cur;
					Node* rightMin = cur->_right;
					while (rightMin->_left) //右子树的最左节点
					{
						rightMinP = rightMin;
						rightMin = rightMin->_left;
					}
					cur->_key = rightMin->_key; //替代

					if (rightMinP->_left == rightMin) //链接
						rightMinP->_left = rightMin->_right;
					else
						rightMinP->_right = rightMin->_right;

					delete rightMin;
					return true;
				}
			}
		}
		return false;
	}

另外我们再增加上一个中序遍历的代码,将中序遍历的代码写在private区域,再在public区域调用这个中序函数,传参直接使用私有成员变量_root会方便许多,代码如下:

template<class K>
class BSTree
{
	typedef BSTNode<K> Node;

	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}
private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}

	Node* _root = nullptr;
};

通过这些就能完成二叉搜索树的模拟实现了。


二叉搜索树的性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二 叉搜索树的深度的函数,即结点越深,则比较次数越多。

但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

左图为最优情况,二叉搜索树接近完全二叉树,其平均比较次数为:O\left ( \log N \right )

右图为最差情况,二叉搜索树退化为类似单支树,其平均比较次数为:O\left ( N \right )


二叉搜索树的应用

K模型

K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。

比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

  1. 以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
  2. 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

 KV模型

每一个关键码Key,都有与之对应的值Value,即<Key,Value>的键值对。该种方式在现实生活中非常常见,英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文就构成一种键值对。STL库中的map和set就是利用了这种模型。

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

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

相关文章

nginx的反向代理及负载均衡

nginx的反向代理 安装包链接https://nginx.org/download/nginx-1.26.1.tar.gz yum -y install gcc gcc-c pcre-devel openssl-devel [rootstaticserver ~]# tar -xzvf nginx-1.26.1.tar.gz [rootstaticserver nginx-1.26.1]#./configure --prefix/usr/local/nginx --userngi…

怎么提高视频的声音?提高视频的声音的多种方法

在制作和编辑视频的浩瀚旅途中&#xff0c;声音质量不仅是引导观众情感波动的舵手&#xff0c;更是构建故事氛围、深化主题表达不可或缺的基石。它如同画面背后的灵魂&#xff0c;悄无声息地牵引着每一位观众的思绪&#xff0c;穿梭于现实与想象的边界。从温馨的旁白讲述到激昂…

单天下载1W+?木途美APP对比体验

在当下的民宿市场&#xff0c;木鸟、途家、美团三家民宿预订平台遥遥领先。木鸟民宿最新发布的报告中提到&#xff0c;7月以来民宿订单环比上涨88%&#xff0c;尽管酒店业进入量涨价跌时代&#xff0c;但民宿平台们似乎活得更好了。 特色房源为王永不过时 房源量大意味着覆盖…

Linux系统之DHCP服务配置

1、准备阶段 Windows&#xff08;客户端&#xff09;开启Vmnet8网卡Linux6&#xff08;服务端&#xff09;网络连接选择NAT模式&#xff0c;并配置IP地址为192.168.11.1/24Linux5&#xff08;客户端&#xff09;网络连接选择NAT模式将NAT的DHCP功能取消 2、DHCP服务器相关软件…

(vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束

(vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束 需求&#xff1a;按勾选的顺序给后端传值 难点&#xff1a;在 Element UI 的 el-cascader 组件中&#xff0c;默认的行为是根据数据的层级结构来显示选项&#xff0c;用户的选择也会基于这种层级结构&#xff0c;el-…

SQL必知必会

SQL必知必会 一些SQL知识&#xff0c;出自极客时间陈旸老师《SQL必知必会》 https://time.geekbang.org/column/intro/100029501 基础 视图 视图作为一张虚拟表&#xff0c;帮我们封装了底层与数据表的接口。它相当于是一张表或多张表的数据结果集。视图的这一特点&#x…

【C/C++】C语言到C++的入门知识点(主要适用于C语言精通到Qt的C++开发入门)

【C/C】C语言到C的入门知识点&#xff08;主要适用于C语言精通到Qt的C开发入门&#xff09; 文章目录 C语言与C的不同C中写C语言代码C语言到C的知识点Qt开发中需要了解的C基础知识namespace输入输出字符串类型class类构造函数和析构函数&#xff08;解析函数&#xff09;类的继…

20240801 每日AI必读资讯

&#x1f50a;OpenAI向ChatGPT Plus用户推出高级语音模式 - 只给一小部分Plus用户推送&#xff0c;全部Plus用户要等到秋季 - 被选中的Alpha 测试的用户将收到一封包含说明的电子邮件&#xff0c;并在其移动应用中收到一条消息。 - 同时视频和屏幕共享功能继续推出&#xff…

【论文速读】| MoRSE:利用检索增强生成技术填补网络安全专业知识的空白

本次分享论文&#xff1a;MoRSE: Bridging the Gap in Cybersecurity Expertise with Retrieval Augmented Generation 基本信息 原文作者&#xff1a;Marco Simoni, Andrea Saracino, Vinod Puthuvath, Maurco Conti 作者单位&#xff1a;意大利比萨国家研究委员会信息学与…

2024 年最新 windows 操作系统搭建部署 nginx 服务器应用详细教程(更新中)

nginx 服务器概述 Nginx 是一款高性能的 HTTP 和 反向代理 服务器&#xff0c;同时是一个 IMAP / POP3 / SMTP 代理服务器。Nginx 凭借其高性能、稳定性、丰富的功能集、简单的配置和低资源消耗而闻名。 浏览 nginx 官网&#xff1a;https://nginx.org/ Nginx 应用场景 静态…

最新保姆级教程使用WildCard开通Claude3升级ChatGPT4.0(2024.8)

如何使用 WildCard 服务注册 Claude3 随着 Claude3 的震撼发布&#xff0c;最强 AI 模型的桂冠已不再由 GPT-4 独揽。Claude3 推出了三个备受瞩目的模型&#xff1a;Claude 3 Haiku、Claude 3 Sonnet 以及 Claude 3 Opus&#xff0c;每个模型都展现了卓越的性能与特色。其中&a…

【rockyLinux·9.4】安装 java jdk

一、安装 java 1.选择版本 yum list | grep jdk各个版本之间的区别&#xff1a; 2.选择了&#xff1a;java-17-openjdk-devel.x86_64&#xff08;开发者版本&#xff09;&#xff0c;开始安装 建议安装在 /usr/local 这个目录下&#xff0c;可以创建一个 app 目录来收录它…

如何高情商处世:小李的职场智慧

如何高情商处世&#xff1a;小李的职场智慧 在职场这片大海中&#xff0c;我们都是游泳者&#xff0c;有的人轻松自如&#xff0c;而有的人却挣扎不已。今天&#xff0c;我要和大家分享一个关于如何用高情商处世的故事&#xff0c;它来自于我的侄子小李。 初出茅庐的小李 小…

SAP BW系统表分享第一弹

有时候想要查看BW系统中存在了多少的表时&#xff0c;包含SAP以及自建表&#xff0c;这个时候我们怎么去找呢&#xff1f; 不要慌&#xff0c;BW系统中也有其对应系统表来存储表对应的信息的&#xff0c;存储所有表信息的是DD02V或者DD02VV&#xff0c;我比较推荐使用DD02VV&a…

CSS实现图片边框酷炫效果

一、前言 我们在浏览一些网页时&#xff0c;经常会看到一些好看酷炫的元素边框效果&#xff08;如下图&#xff09;&#xff0c;那么这些效果是怎么实现的呢&#xff1f;我们知道&#xff0c;一般的边框&#xff0c;要么是实线&#xff0c;要么是虚线&#xff08;点状&#xf…

python随机选取数据算法

python随机选取数据算法&#xff1a; 使用sample方法 pandas的sample方法是最常用的方法来随机选取DataFrame中的数据。可以通过设置frac参数来指定选取的比例。 代码&#xff1a; import pandas as pd# 创建一个示例DataFrame data {A: range(1, 101),B: range(101, 201) }…

大厂linux面试题攻略四之Linux网络服务(一)

一、Linux网络服务-SSH服务 1.哪些设置能够提升SSH远程管理的安全等级? ssh的登录验证方式 ssh的登录端口和监听设置&#xff1a; 配置文件: /etc/ssh/sshd_config #Port 22 #ssh服务默认监听端口 #ListenAddress 0.0.0.0 #ssh服务…

配置静态IP,解决在虚拟机装Linux没有网络的问题

配置静态IP&#xff0c;解决在虚拟机装Linux没有网络的问题 问题 VMware中的虚拟机有时会随着外部宿主机的IP变化而变化&#xff0c;导致使用起来很麻烦。最直接的就是XShell连接不上&#xff0c;其次就是项目中的配置文件中写了关于虚拟机的ip地址&#xff0c;比如redis mys…

编程小白如何成为大神?大学新生的最佳入门攻略

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

【视频讲解】Python用LSTM、Wavenet神经网络、LightGBM预测股价

原文链接&#xff1a;https://tecdat.cn/?p37184 原文出处&#xff1a;拓端数据部落公众号 分析师&#xff1a;Yuyan Ye 在金融科技的浪潮中&#xff0c;量化投资方法以其数据驱动和模型导向的特性&#xff0c;日益成为资本市场分析的重要工具。 特别是&#xff0c;长短期…