C++实现二叉搜索树(模型)

目录

1.二叉搜索树的概念

2.二叉搜索树的实现

2.1总体代码预览

2.2各个函数实现原理

链表结构体

二叉搜索树的成员变量

二叉搜索树的插入

二叉搜索树的查找

二叉搜索树的遍历

二叉搜索树的删除


1.二叉搜索树的概念

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

1.若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

2.若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

3.它的左右子树也分别为二叉搜索树

2.二叉搜索树的实现

由上面的定义,我们知道二叉搜索树的左孩子是小于父亲的,而右孩子是大于父亲的。由这个规律我们就可以实现一下这个二叉搜索树。

2.1总体代码预览

template<class k>
	struct BSTreeNode
	{
		BSTreeNode<k>* _left;
		BSTreeNode<k>* _right;
		k _key;

		BSTreeNode(const k& key)
			:_left(nullptr)
			,_right(nullptr)
			,_key(key)
		{}

	};


	template<class K>
	class BST
	{
		typedef BSTreeNode<K> Node;
	public:
		bool Insert(const K& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}
			Node* parent = nullptr;
			Node* cur = _root;
			
			while (cur)
			{
				if (key > cur->_key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (key < cur->_key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}
			cur = new Node(key);
			if (key < parent->_key)
			{
				parent->_left = cur;
			}
			else
			{
				parent->_right = cur;
			}
			return true;
		}
		bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (key > cur->_key)
				{
					cur = cur->_right;
				}
				else if (key < cur->_key)
				{
					cur = cur->_left;
				}
				else
				{
					return true;
				}
			}
			return false;
		}
		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;

			while (cur)
			{
				if (key > cur->_key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (key < cur->_key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//删除
					if (cur->_left == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_right;
							}
							else if (parent->_right == cur)
							{
								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 if (parent->_right == cur)
							{
								parent->_right = cur->_left;
							}
						}
						delete cur;
					}
					//cur左右都不为空
					else
					{
						Node* rightminparent = cur;
						Node* rightmin = cur->_right;
						while (rightmin->_left)
						{
							rightminparent = rightmin;
							rightmin = rightmin->_left;
						}
						swap(rightmin->_key, cur->_key);
						if(rightminparent->_left== rightmin)
							rightminparent->_left = rightmin->_right;
						else
							rightminparent->_right = rightmin->_right;
						delete rightmin;
					}
					return true;
				}
			}
			return false;
		}
		
		void InOrder()
		{
			_InOrder(_root);
		}
	private:
		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}

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

		}
		Node* _root=nullptr;
	};

2.2各个函数实现原理

链表结构体

template<class k>
	struct BSTreeNode
	{
		BSTreeNode<k>* _left;
		BSTreeNode<k>* _right;
		k _key;

		BSTreeNode(const k& key)
			:_left(nullptr)
			,_right(nullptr)
			,_key(key)
		{}

	};

既然是我们的二叉树,那么链表的部分肯定是不能少的吧,这个链表里面,我们来定义左右孩子的指针,还有用来进行标识的key值,接下来就可以写一下它的构造函数,这个节点一开始肯定是没有左右孩子的,所以我们给它们赋上空指针,而key就是我们传的key。

二叉搜索树的成员变量

Node* _root=nullptr;

二叉搜索树的成员变量就很简单了,我们直接定义一个结构体指针的变量的就可以了。Node类型是我们重命名链表名后的名字。

二叉搜索树的插入

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

插入的逻辑其实非常简单,如果这棵树是一棵空树,那么我们直接创个根节点就可以了,不需要后续的操作,倘若不是空树,那我们就进行接下来的操作,我们先定义一个父亲节点parent和当前节点cur,然后按照我们的性质,key比cur中的大我们就往右,小的话我们就往左走,如果这个key在树中存在,我们就放回false,因为set是有去重功能的,就是说一棵树里不能存在两个一样的值。找到了适合的位置我们就出循环,然后开始创建节点,进行连接就可以了。

二叉搜索树的查找

bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (key > cur->_key)
				{
					cur = cur->_right;
				}
				else if (key < cur->_key)
				{
					cur = cur->_left;
				}
				else
				{
					return true;
				}
			}
			return false;
		}

查找的功能就更简单了,我们只需要按照性质,左边比根小右边比根大就可以了。

二叉搜索树的遍历

void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}

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

		}

我们的二叉搜索树按照中序遍历是刚好是有序的,这个是我们二叉搜索树的意义之一,所以我们这里也是实现中序遍历。

中序遍历的思想就简单的多了,使用递归对它的各个节点进行遍历就可以了。

但是我们调用中序遍历肯定不想别人传个参数,所以我们再进行封装就可以了。

二叉搜索树的删除

bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;

			while (cur)
			{
				if (key > cur->_key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (key < cur->_key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//删除
					if (cur->_left == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_right;
							}
							else if (parent->_right == cur)
							{
								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 if (parent->_right == cur)
							{
								parent->_right = cur->_left;
							}
						}
						delete cur;
					}
					//cur左右都不为空
					else
					{
						Node* rightminparent = cur;
						Node* rightmin = cur->_right;
						while (rightmin->_left)
						{
							rightminparent = rightmin;
							rightmin = rightmin->_left;
						}
						swap(rightmin->_key, cur->_key);
						if(rightminparent->_left== rightmin)
							rightminparent->_left = rightmin->_right;
						else
							rightminparent->_right = rightmin->_right;
						delete rightmin;
					}
					return true;
				}
			}
			return false;
		}

二叉搜索树的删除才是我们的真正难点

我们最开始的操作还是一样的,我们要找那个被删除的节点,找到后就开始我们的操作了。我们有三种大情况:

第一种是要删除的节点左孩子为空的时候:

如图所示,我们的cur只有一边是有值的,这个时候我们先判断这个cur是父亲的左孩子还是右孩子,然后再把链表指向修改就行了,但是不要忘记了,我们的cur有可能是根节点,这个时候我们的父亲节点是空,这个时候是没法去给parent修改指向的,所以我们要单独的写一个判断。

第二种自然就是右孩子为空了,思路跟左孩子是一模一样的。

第三种就是我们的cur的左右孩子都不为空,这里的做法右两种,第一种是找cur的左子树的最大值,替换cur,然后再把cur给删除,第二种是找右子树的最小值,然后进行同样的操作,这两种做法都可以使其保持二叉搜索树该有的性质。这里我们选择第二种。

可以看到外面用循环来找到右子树的最小值,找到后交换值,我们没有直接让rightminparent的左节点直接接向rightmin的右子树是因为可能有这种情况

假如我们删的是8,这个时候右孩子是没有左节点的,这个时候我们就不可能rightminparent的左节点接向rightmin的右子树,所以我们进行了这个分类讨论,这个细节也是很难想到的。

至此我们的二叉搜索树的实现原理就讲完了,感谢大家的收看!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CSS中文本样式(详解网页文本样式)

目录 一、Text介绍 1.概念 2.特点 3.用法 4.应用 二、Text语法 1.文本格式 2.文本颜色 3.文本的对齐方式 4.文本修饰 5.文本转换 6.文本缩进 7.color&#xff1a;设置文本颜色。 8.font-family&#xff1a;设置字体系列。 9.font-size&#xff1a;设置字体大小。…

做好源代码防泄密的10条准则

#深度好文计划# 近年来&#xff0c;电脑以及互联网应用在中国的普及和发展&#xff0c;已经深入到社会每个角落&#xff0c; 政府&#xff0c;经济&#xff0c;军事&#xff0c;社会&#xff0c;文化和人们生活等各方面都越来越依赖于电脑和网络。企业需要花费大量的时间精力去…

PC小程序解密及反编译

一、小程序包解密 小程序原始加密包位置C:\Users\administrator\Documents\WeChat Files\Applet\wx234324324324 二、wxappUnpacker反编译 npm install./bingo D:\temp\小程序包解密\wxpack\wx234324324324.wxapkg 三、查看反编译后的文件

Fluence Developer Rewards 国内 每个账号收2000元

# 国内有金主支持 每个账号收2000元 Fluence Developer Rewards account_line 白名单见附件 # 感兴趣的请留言 或加微信 Fluence Developer Rewards This repo allows one to generate a proof signature for Fluence dev reward claiming. 感兴趣 Caution Beware of s…

MapReduce的Shuffle过程

Shuffle是指从 Map 产生输出开始,包括系统执行排序以及传送Map输出到Reduce作为输入的过程. Shuffle 阶段可以分为 Map 端的 Shuffle 阶段和 Reduce 端的 Shuffle 阶段. Shuffle 阶段的工作过程,如图所示: Map 端的 Shuffle 阶段 1&#xff09;每个输入分片会让一个 Map 任务…

STM32F407VET6 学习笔记1:GPIO引脚认识分类与开发板原理图

今日学习STM32F407VET6 &#xff0c;首先从基本原理图、引脚方面开始做个初步理解并整理&#xff1a; 这里使用的学习开发板是在嘉立创购买的 立创梁山派天空星&#xff0c;芯片是 STM32F407VET6 主要对这个芯片的引脚做一些归纳认识、对开发学习板原理图设计进行认识理解:最…

上传文件至linux服务器失败

目录 前言异常排查使用df -h命令查看磁盘使用情况使用du -h --max-depth1命令查找占用空间最大的文件夹 原因解决补充&#xff1a;删除文件后&#xff0c;磁盘空间无法得到释放 前言 使用XFTP工具上传文件至CentOS服务器失败 异常 排查 使用df -h命令查看磁盘使用情况 发现磁盘…

IDEA中git的常用操作(保姆级教学)

IDEA中git的常用操作&#xff08;保姆级教学&#xff09; 以下是git的工作原理&#xff0c;觉得繁琐的可以跳过不看 Workspace&#xff1a;工作区 (平时存放代码的地方) Index / Stage&#xff1a;暂存区&#xff08;用于临时存放存放你的改动&#xff0c;事实上就是一个文件&…

电脑实时监控软件分享|好用实时屏幕监控软件有哪些?

在当今数字化工作环境和远程办公日益普及的背景下&#xff0c;电脑实时监控软件成为了企业管理、教育监控、家庭监护等多个领域的必备工具。这些软件不仅能够帮助管理者实时了解员工的工作状态&#xff0c;确保工作效率&#xff0c;还能有效防止数据泄露&#xff0c;保护企业或…

现场面试题

这里写目录标题 1.sql1.1 只保留学生的最新成绩1.2 统计通话号码数1.3 更新地址 2.基础题2.1 请求序列第N位的值: 0, 1, 1, 2, ,3, 5, 8, 13, 21, 34.....第N位的值2.2 请写一段java代码&#xff0c;输出存在重复字母的单词 1.sql 1.1 只保留学生的最新成绩 表student中记录学…

Vue-组件中的data

一个组件的data选项必须是一个函数。保证每个组件实例&#xff0c;维护独立的一份数据对象。如下图&#xff1a; 组件一旦封装好了&#xff0c;可以使用多次&#xff0c;比如数字框组件使用了三次&#xff1a; 每次创建新的组件实例&#xff0c;都会重新执行一次data函数&#…

leetcode-字符串的排列-100

题目要求 思路 1.因为只涉及到字符&#xff0c;因此可以进行排序 2.创建临时字符串&#xff0c;当临时字符串temp的长度等于str的长度&#xff0c;作为判出条件。 3.创建一个标记的数组&#xff0c;每次在temp中插入一个字符&#xff0c;便在对应的数组下标设置为1&#xff0c…

【PDF技巧】PDF限制编辑密码忘记了,如何编辑文件?

PDF文件打开之后&#xff0c;发现编辑功能都是灰色的&#xff0c;无法使用&#xff0c;无法编辑PDF文件&#xff0c;遇到这种情况&#xff0c;是因为PDF文件设置了限制编辑导致的。一般情况下&#xff0c;我们只需要输入PDF密码&#xff0c;将限制编辑取消就可以正常编辑文件了…

【ARM Cortex-M3指南】8:中断行为

文章目录 八、中断行为8.1 中断/异常流程8.1.1 压栈8.1.2 取向量8.1.3 寄存器更新 8.2 异常退出8.3 嵌套中断8.4 末尾连锁中断8.5 延迟到达8.6 进一步了解异常返回值8.7 中断等待8.8 中断相关的错误8.8.1 压栈8.8.2 出栈8.8.3 取向量8.8.4 非法返回 八、中断行为 8.1 中断/异常…

GPU术语

可向量化循环 可向量化循环通常是指在编程中&#xff0c;能够被转换为向量操作或矩阵运算的循环结构。 在传统编程中&#xff0c;对于数组或向量中的每个元素执行相同的操作时&#xff0c;开发者可能会使用for循环逐一进行处理。然而&#xff0c;许多现代编程语言和库提供了向…

从哪些方面可以看出现货黄金价格走势?

现货黄金价格的走势受到多种因素的影响&#xff0c;我们可以从宏观经济环境、货币政策、供需关系、市场情绪和技术分析几个主要方面来观察和分析这一贵金属的价格动态。现货黄金作为全球投资市场中的避险资产&#xff0c;其价格波动往往能体现出复杂的经济和政治变化。 宏观经济…

(论文阅读-优化器)Orca: A Modular Query Optimizer Architecture for Big Data

目录 摘要 一、简介 二、背景知识 2.1 大规模并行处理 2.2 SQL on Hadoop 三、Orca架构 四、查询优化 4.1 优化工作流 4.2 并行查询优化 五、Metadata Exchange 六、可行性 6.1 Minimal Repros 6.2 优化器准确性测试 七、实验 八、相关工作 8.1 查询优化基础 8…

Python专题:二、Python小游戏,体验Python的魅力

希望先通过一个小的游戏让大家先对Python感兴趣&#xff0c;兴趣是最好的老师。 小游戏的运行结果&#xff1a; 1、在sublime编辑器里面写如下代码&#xff1a; import randomnum random.randint(1, 100) # 获得一个随机数 is_done False # 是否猜中的标记 count 0 # 玩…

视频号小店怎么做?品从哪里来?如何推广售卖?一文详解

大家好&#xff0c;我是电商笨笨熊 视频号小店作为一个刚推出不久的项目&#xff0c;可谓是站在风口&#xff0c;遍地红利&#xff0c;也正是我们进入的最佳时机。 但是面对一个新的项目&#xff0c;自是存在着多种疑问&#xff0c;尤其是对于一些从未踏足电商市场的新手玩家…

SpringBoot+Vue+Element-UI实现医患档案管理系统

目录 前言介绍 系统展示 管理员页面 患者管理 诊疗信息管理 病历信息管理 处方信息管理 患者页面 医生页面 部分核心代码 病历信息 上传文件 数据库配置 前言介绍 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技…