C++实现基础二叉搜索树(并不是AVL和红黑树)

news2024/11/19 13:31:27

本次实现的二叉搜索树并不是AVL数和红黑树,只是了解流程和细节。

目录

  • 二叉搜索树的概念
  • K模型二叉搜索树的实现
    • 二叉搜索树的架构
    • insert插入
    • find 查找
    • 中序遍历Inorder
    • 删除earse
      • 替换法的思路
      • 情况一 :假如要删除节点左边是空的。
        • 在左边时
        • 在右边时
      • 情况二:假如要删除节点右边是空的。
        • 是父亲的右边时
        • 是父亲的左边时
      • 情况三:两边都有值
        • 左边
        • 右边
        • 代码实现

二叉搜索树的概念

二叉搜索树并不是单纯存储数据。所以他有规则:
①.左子树比根小,右子树比根大。

②.搜索二叉树不建议用递归。

二叉搜索树一定要遵循这个规律!否则他都不能算是二叉搜索树!

K模型二叉搜索树的实现

二叉搜索树的架构

我们之前也学过二叉树,二叉树的结构是节点里面放了左右指针和值,所以节点就是一下结构。 而二叉树的本身就是又一个根节点连接起来的

template<class T>
struct BinarySearchTreeNode
{
	BinarySearchTreeNode(T& key)
		:_key(key)
		, _left(nullptr)
		, _right(nullptr)
	{}
	T _key;
	BinarySearchTreeNode* _left;
	BinarySearchTreeNode* _right;
};
	template<class T>
	class BinarySearchTree
	{
	public:
		typedef BinarySearchTreeNode<T> Node;		
	private:
		Node* _root=nullptr;
	};

insert插入

插入一定要遵循规则:
①.左子树比根小,右子树比根大。
不是这个规则都不是二叉搜索树。

(1). 当你插入第一个值的时候,他就是根,所以我们要特殊处理,当_root==nullptr时,要把第一个插入的值变成根。
(2).除第一个值之后的值就要遵行规则。

bool insert(T& x)
{
	if (_root == nullptr)
	{
		Node* noeNode = new Node(x);
		_root = noeNode;
		return true;
	}
	Node* cur = _root;
	Node* parent = cur;
	while (cur)
	{
		if (cur->_key < x)
		{
			//大于在右边
			parent = cur;
			cur = cur->_right;

		}
		else if (cur->_key > x)
		{
			//小于在左边
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			//等于,二叉搜索树不允许冗余,所以直接返回false。
			return false;
		}

	}
	Node* newNode = new Node(x);
	if (newNode->_key > parent->_key)
		parent->_right = newNode;
	else
		parent->_left = newNode;
	return true;
}

find 查找

查找就很简单,只要把前面的代码复制一半,当查找到了,我们就返回true,到空了都没找到就返回false。

bool find(const T& x)
{
	Node* cur = _root;
	Node* parent = cur;
	while (cur)
	{
		if (cur->_key < x)
		{
			//大于在右边
			parent = cur;
			cur = cur->_right;

		}
		else if (cur->_key > x)
		{
			//小于在左边
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			//等于,找到了
			return true;
		}

	}
	return false;
}

中序遍历Inorder

中序遍历我们都很了解了,但是问题是,我们要把根传入,根一定是私有的,你在类外访问不了。这个时候我们就可以套一层。

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

删除earse

删除其实很麻烦,有很多种情况。因为二叉搜索数一定是满足规则的,所以我们删除不能混乱了规则,而是继续保持规则。所以我们要用替换法,保证规则不乱

替换法的思路

因为我们要保证规则不乱,那么我们可以用替换法,让左树的最大值/右树的最小值与当前值替换,因为当前节点的左边一定比他小,右边一定比他大,那么当我们用左边最大值,替换了当前节点,也不会改变规则;右边同理。

情况一 :假如要删除节点左边是空的。

在左边时

假如我要删除9这个节点。并且左侧是空,那么我们是不是可以直接让他父亲的左边指向他的右边?思考一下!

为什么?左侧为空,当前删除节点的左侧一定是什么都没有的,右边可有可无,但是右边没有也没关系,一样置空,有的话,我们就需要让他的父亲链接他的孩子。
在这里插入图片描述
并且我们发现并不用替换法,就可以直接链接后删除。
在这里插入图片描述

在右边时

其实在右边也是一样的,只不是我们要特殊判断一下,删除节点时父亲的左边还是右边,方便我们链接。
在这里插入图片描述

情况二:假如要删除节点右边是空的。

是父亲的右边时

那么他右边一定是没有值的,左边的值可有可无,那么我们就需要让它的父亲指向他的左值就可以了。
在这里插入图片描述

是父亲的左边时

在这里插入图片描述

情况三:两边都有值

如果这棵树是这样的,那么我要删除9怎么做呢?就需要替换法,我们需要找左边最大值或者右边最小值,我们假设要找是右边最小值
在这里插入图片描述

从当前节点开始找,右边最小值是10(蓝色标记)。

问:为什么要从当前节点找,而不是从根开始?
答:如果从根开始找,你会发现,当我们交换后,不满足条件了。图中右边最小值是13,如果换到最左边那就不满足二叉搜索的要求了,所以要从当前节点找,因为当前节点的右边跟当前这个位置换一定是比大,比其他节点小的。

在这里插入图片描述
当我们都找到了,我们就要用交换法。将两个值交换后,左边最小的那个节点就是我们要删除的。那么我们就需要把最小节点的右边给它的右边。
在这里插入图片描述

左边

这里给大家道个歉,因为数字太过紧凑,所以凑不出数,只能让整型和浮点数混合了,在实际场景中是不可能有的,只是举个例子

假设我们交换后,发现要删除的节点右边还有值,

问题:我怎么让被删除节点的父亲知道是左边还是右边的节点间接我的右节点呢
答:需要判断一下,如果被删除的节点是父亲的左边,就需要让左边指向被删的右边,如果是父亲的右边就让父亲的右边指向被删的右边。

在这里插入图片描述
在这里插入图片描述

右边

这种情况,就是他在父亲的右边,所以我们需要让父亲的右边链接被删的右边。
在这里插入图片描述

代码实现

虽然删除的代码很复杂,但是要注意的细节很多。
(1).在我们找到了当前被删节点,情况三的时候,能不能让Node* rightMinParent = nullptr;? 答:不可以,因为当我们删除这种情况的时候,就会导致空指针访问,因为循环我们没有进去,但是链接值的时候,就会导致空指针访问。

(2).在我们交换后,能不能递归把他删了?不能!我问你交换后还满足二叉搜索数的要求吗?不满足,你永远都不会找到!

在这里插入图片描述

		bool erase(const T& x)
		{
			Node* cur = _root;
			Node* parent = cur;
			while (cur)
			{
				if (cur->_key < x)
				{
					//大于在右边
					parent = cur;
					cur = cur->_right;

				}
				else if (cur->_key > x)
				{
					//小于在左边
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//等于,找到了

					if (cur->_left == nullptr)
					{
						//没有值直接删,把右边给父亲
						if (cur == parent->_left)
						{
							parent->_left = cur->_right;
							delete cur;
						}
						else if(cur == parent->_right)
						{
							parent->_right = cur->_right;
							delete cur;
						}
					}
					else if (cur->_right == nullptr)
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_left;
							delete cur;
						}
						else if (cur == parent->_right)
						{
							parent->_right = cur->_left;
							delete cur;
						}
					}
					else
					{
						Node* rightMin = cur->_right;
						Node* rightMinParent = cur;
						//这里要让父亲是cur,删根的时候就会出问题
						while (rightMin->_left)
						{
							rightMinParent = rightMin;
							rightMin = rightMin->_left;
						}
						std::swap(cur->_key, rightMin->_key);
						if (rightMinParent->_left == rightMin)
							rightMinParent->_left = rightMin->_right;
						else
							rightMinParent->_right = rightMin->_right;
						delete rightMin;
					}
					return true;
				}
			}
			return false;
		}

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

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

相关文章

罗德里格斯公式(旋转矩阵)推导

文章目录 1. 推导2. 性质3. 参考 1. 推导 r r r为旋转轴&#xff0c; θ \theta θ为旋转角度。 先将旋转轴单位化 u r ∣ ∣ r ∣ ∣ u\frac{r}{||r||} u∣∣r∣∣r​ 旋转可以被分为垂直和旋转两个方向&#xff0c; 我们求沿轴方向的分量其实就是在求 p p p向量在 u u u方…

新时代AI浪潮下,程序员和产品经理如何入局AIGC领域?

当下&#xff0c;AI浪潮席卷全球&#xff0c;AIGC大模型技术已经成为当今技术领域的一个重要趋势&#xff0c;对于产品经理来说&#xff0c;掌握这项技术不仅能够增强他们的职业技能&#xff0c;还能在竞争激烈的职场中脱颖而出。 为什么呢&#xff1f; 把握AI时代的机遇 AI技…

arcgisPro精确移动要素某一点至指定点位

1、打开要素&#xff0c;如下&#xff1a; 2、选择移动工具&#xff0c;如下&#xff1a; 3、选择需要移动的要素&#xff0c;如下&#xff1a; 4、按住Ctrl键&#xff0c;移动锚点的位置至三角形顶点位置&#xff0c;如下&#xff1a; 5、拖动锚点至上面多边形的左上角点&…

java语言概述和代码的编译

文章目录 前言 一、机器语言 二、汇编语言 三、高级语言 四、编写代码 打印字符串 求前n项和 五、问题及解决 总结 前言 计算机经过了多年的发展&#xff0c;已经诞生了很多编程语言&#xff0c;如早期的汇编语言&#xff0c;basic语言&#xff0c;现在的高级语言C语言java语言…

提取COCO 数据集的部分类

1.python提取COCO数据集中特定的类 安装pycocotools github地址&#xff1a;https://github.com/philferriere/cocoapi pip install githttps://github.com/philferriere/cocoapi.git#subdirectoryPythonAPI若报错&#xff0c;pip install githttps://github.com/philferriere…

为什么股票市场里有认贼为父的现象?

文章大纲&#xff1a;&#xff08;本文2648字&#xff0c;完整版本应该3500以上&#xff0c;耗时一个钟&#xff09; 1、前言&#xff1a;逻辑与博弈 2、直觉引入博弈焦点 3、上周4-5的市场博弈视角 4、下周一视角能看到的东西 5、视角背后看到的情绪周期市场共识下的博弈…

大摩:AI到“临界点”了,资管公司到了广泛部署的时刻

大摩表示&#xff0c;尽管AI技术在资产管理行业中的应用仍处于早期阶段&#xff0c;但其潜力巨大&#xff0c;能够为行业带来根本性的变革。预计生成式AI能够在资产管理公司的运营模型中带来20%至40%的生产力提升。 正文介绍 在全球经济面临诸多不确定因素的当下&#xff0c;…

事务管理控制

文章目录 1. 事务的基本概念2. 数据库的并发控制2.1 事务调度2.2 并发操作带来的问题2.3 并发调度的可串行性2.4 并发控制技术2.5 两段锁协议2.6 多粒度封锁协议 3. 数据库的备份与恢复3.1 数据库系统故障3.2 数据库的备份3.3 数据库的恢复 4. 数据库的安全性与完整性4.1 数据库…

01-Linux【准备篇】

一、学Linux的作用&#xff1f; 1.Linux下开发(部署)软件项目 2.Linux运维 二、Linux的强与弱 1.薄弱 个人桌面领域的应用 此领域是传统Linux应用薄弱的环节&#xff0c;近些年随着Ubuntu、fedora等优秀桌面环境的兴起&#xff0c;Linux在个人桌面领域的占有率在慢慢提高…

如何用AI工具提升日常工作效率,帮我们提速增效减负

昨天&#xff0c;coze海外版支持了GPT4o&#xff0c; 立马体验了下&#xff0c;速度杠杠的。 https://www.coze.com 支持chatGP和gemini模型&#xff0c;需要科学上网。国内 https://www.coze.cn支持语雀、KIMI模型。 这里回到正题&#xff0c; 如何用AI工具提升日常工作效率…

【LeetCode】30.串联所有单词的子串

串联所有单词的子串 题目描述&#xff1a; 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。 s 中的 串联子串 是指一个包含 words 中所有字符串以任意顺序排列连接起来的子串。 例如&#xff0c;如果 words ["ab","cd",&qu…

【智能算法应用】北方苍鹰算法求解二维栅格路径规划问题

目录 1.算法原理2.二维路径规划数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】北方苍鹰优化算法&#xff08;NGO)原理及实现 2.二维路径规划数学模型 栅格法模型最早由 W.E. Howden 于 1968 年提出&#xff0c;障碍物的栅格用黑色表示&#xff0c;可通过的…

草图大师怎么去画好一个建筑别墅su模型呢?

其实&#xff0c;我们经常画别墅的时候&#xff0c;都会要画别墅&#xff0c;我们画一个欧式风格的别墅&#xff0c;要在草图大师中创建一个优秀的建筑别墅模型&#xff0c;可以按照以下步骤进行&#xff1a; skp模型库 1.收集参考资料&#xff1a; 在开始之前&#xff0c;收集…

当前时机是否适合进入 AIGC 行业:行业发展与市场需求分析

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

如何成为成功的AI产品经理

本文目录 1 AI产品经理的角色和职责 2 AI产品经理的必备知识技能 3 案例分析 4 总结一下 随着ChatGPT的大热&#xff0c;也带动今年的AI火了一把&#xff0c;很多公司都开始进行相关部署&#xff0c;自然产生了很多岗位需求。 来源&#xff1a;BOSS直聘 那么&#xff0c;要想当…

Training-Free Consistent Text-to-Image Generation # 论文阅读

URL https://arxiv.org/pdf/2402.03286 TL;DR 2024 年 2 月 nvidia 的文章。提出了一种不需要任何额外训练的主体保持方法&#xff0c;可以一次生成的 batch 中&#xff0c;通过多个 prompt 生成对应的多张图片&#xff0c;这些图片都可以拥有一个主体。 本文提出的方法通过…

【JavaEE 初阶(十)】JVM

❣博主主页: 33的博客❣ ▶️文章专栏分类:JavaEE◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多进阶知识 目录 1.前言2.JVM内存区域划分3.类加载3.1双亲委派模型 4.垃圾回收&#xff08;GC&#xff0…

游戏后台开发技术全面解析

在这个数字时代&#xff0c;游戏产业已经成为全球最受欢迎的娱乐方式之一。从简单的手机游戏到复杂的大型多人在线角色扮演游戏&#xff08;MMORPG&#xff09;&#xff0c;游戏的世界正变得越来越丰富和多样化。而这一切的背后&#xff0c;都离不开强大的游戏后台技术支持。在…

心理咨询系统|心理咨询系统开发|心理咨询软件开发

在快节奏的现代生活中&#xff0c;心理健康问题越来越受到人们的关注。为了有效应对这些问题&#xff0c;心理咨询系统应运而生&#xff0c;它为人们提供了一个安全、便捷的平台&#xff0c;以寻求心理帮助和支持。本文将详细介绍心理咨询系统的功能、优势以及未来发展趋势。 …

【C语言】指针运算

前言 前面在“走进指针世界”中我已经讲解过指针相关的很多前置知识&#xff0c;其实还有一个很重要的部分就是指针的运算。这篇博客&#xff0c;就让我们一起了解一下指针的运算吧&#xff01; 指针作为变量&#xff0c;是可以进行算术运算的&#xff0c;只不过情况会和整型…