这是一棵适合搜索二叉树

news2024/9/21 18:54:26

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻强烈推荐优质专栏: 🍔🍟🌯C++的世界(持续更新中)
🐻推荐专栏1: 🍔🍟🌯C语言初阶
🐻推荐专栏2: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:"二叉搜索树"的模拟实现
金句分享:
✨远赴人间惊鸿宴,一睹人间盛世颜!✨

目录

  • 一、什么是"二叉搜索树"?
  • 二、"二叉搜索树"的实现
    • 结点结构
    • "二叉搜索树":的结构
    • (1) "插入"操作
    • (2) "查找"操作
    • (3) "删除"操作 (重点)
    • (4)"中序"遍历
  • 三、结语

一、什么是"二叉搜索树"?

二叉搜索树(Binary Search Tree)又称为二叉查找树,是一种常用的数据结构。它是一棵空树,或者是具有以下性质的二叉树:

  1. 左子树上所有结点的值都小于它的根结点的值。
  2. 右子树上所有结点的值都大于它的根结点的值。
  3. 左右子树也分别为二叉搜索树。

错误示例1:
在这里插入图片描述
错误示例2:
在这里插入图片描述

正确示例:
在这里插入图片描述

二、"二叉搜索树"的实现

本篇文章实现的是键值对也就是(key,value)版本的 “二叉搜索树”.
Key-value版本的二叉搜索树(BST)是一种基于二叉树数据结构的数据结构,其中每个节点都存储一个键-值对。在该数据结构中,每个节点都具有一个唯一的关键字,该关键字用于对节点进行排序.

如下是树中每个结点的结构:

结点结构

template<class K, class V>
struct BSTreeNode
{
	BSTreeNode(const K& key = K(), const V& value = V())
		: _left(nullptr), _right(nullptr), _key(key), _value(value)
	{}
	BSTreeNode<K,V>* _left;
	BSTreeNode<K,V>* _right;
	K _key;							//关键码,用于比较大小的,按key比较
	V _value;						//用于存储数据
};

“二叉搜索树”:的结构

template<class K, class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;		//注意这里的类型重命名
public:
	bool Insert(const K& key, const V& value);
	Node* Find(const K& key);
	bool Erase(const K& key);
	void _InOrder(Node* root);
	void InOrder();
private:
	Node* _root = nullptr;
};

(1) "插入"操作

根据"二叉搜索树"的特性,我们不难知道,左子树 < 根 < 右子树.

  1. 如果是空树,则表明新插入的结点将作为根节点.
  2. 如果不是空树,则先找到该插入的位置,再链接即可.

示例:如果在插入一个结点值为9的结点.

寻找过程:
比根节点8大,所以往右找.
12小,所以往左找.
11小,所以往左找.
11的左边为空,寻找结束.

9结点插入到11的左边.

在这里插入图片描述

//插入操作
template<class K, class V>
bool BSTree<K,V>::Insert(const K& key, const V& value)
{
	//如果是空树,则直接赋值给根节点
	if (_root == nullptr)
	{
		//没看清node结构的,可以翻到上面在看一下构造函数.
		_root = new Node(key,value);	//用值构建结点,并赋给根节点
		return true;
	}

	//如果不是 空树
	Node* cur = _root;			//代替根节点遍历树,寻找插入位置.
	Node* pnode = nullptr;		//记录目标位置的父亲结点
	while (cur)				//一直找到nullptr为止
	{
		pnode = cur;				//更新父节点
		if (key > cur->_key)		//如果插入的键值对 key 比当前元素的key大,则往右走
		{
			cur = cur->_right;
		}
		else if (key < cur->_key)		//如果插入的值比当前元素小,则往左走
		{
			cur = cur->_left;
		}
		else return false;			//相等则返回false
	}

	//判断插入在左边还是右边
	Node* newnode = new Node(key, value);
	if (key < pnode->_key)
	{
		pnode->_left = newnode;
	}
	else
	{
		pnode->_right = newnode;
	}
	return true;
}

(2) "查找"操作

友友们插入操作都能轻松拿捏,那find还不是轻松拿捏?

小注意:
如果函数是在类里面声明,类外面定义,则需要注意一个小问题.
Node是一个类型还是一个变量(静态成员变量可以通过类名+ ::访问),所以需要在前面加上一个关键字typename ,告诉编译器这是一个类型.

template<class K, class V>
typename BSTree<K,V>::Node* BSTree<K, V>::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 cur;			//相等则说明找到了
	}
	return nullptr;
}

(3) "删除"操作 (重点)

删除操作应该是"二叉搜索树"最难的操作了,这里牛牛就讲解的仔细一点吧!

(1)情况1: 目标结点没有孩子.
处理方法:找到该结点 和 该结点的父亲,直接删除即可.
在这里插入图片描述

(2)情况2:目标结点只有一个孩子,可能是左孩子,也可能是右孩子.
处理方法:
只有左孩子时:
让父亲不再指向自己(这里要判断自己在父亲的左还是右),而是指向自己的左孩子,然后再删除自己.
在这里插入图片描述

只有右孩子时:
让父亲不再指向自己(这里要判断自己在父亲的左还是右),而是指向自己的右孩子,然后再删除自己.
在这里插入图片描述

情况3: 目标结点有两个孩子.

右子树最小节点:
在这里插入图片描述

左子树最大节点:
在这里插入图片描述

代码实现:

template<class K, class V>
bool BSTree<K, V>::Erase(const K& key)
{
	if (_root == nullptr)
	{
		cout << "空树不可删除" << endl;//空树无法删除
		return false;
	}

	//寻找目标结点的位置

	Node* pnode = nullptr;		//记录当前结点的父亲结点
	Node* cur = _root;			//当前结点:代替根节点遍历树.

	//寻找目标结点
	while (cur)
	{

		if (key > cur->_key)		//如果插入的值比当前元素大,则往右走
		{
			pnode = cur;
			cur = cur->_right;
		}
		else if (key < cur->_key)		//如果插入的值比当前元素小,则往左走
		{
			pnode = cur;
			cur = cur->_left;
		}
		else  break;			//相等则说明找到了
	}

	//表示在树中 未找到
	if (cur == nullptr) { return false; }
	
	//这里采取与右子树的最小结点替换的方法
	if (cur->_right && cur->_left)//如果有两个孩子
	{
		Node* p_left_max = nullptr;			//右树 的最小节点的父亲
		Node* left_max = cur->_right;		//右树 的最小节点
		//寻找目标结点 右树 的最小节点
		while (left_max->_left)
		{
			p_left_max = left_max;
			left_max = left_max->_left;
		}
		//替换
		cur->_key = left_max->_key;		//其实覆盖即可
		cur->_value = left_max->_value;

		//将原右子树的最小结点的父亲与 右树最小结点断绝关系
		p_left_max->_left = nullptr;
		delete left_max;					//删除右树最小结点
		return true;
	}

	// 要删除的节点只有一个子节点或没有子节点
	Node* child = nullptr;
	//这样child就是孩子
	if (cur->_left)	//只有左孩子
	{
		child = cur->_left;
	}
	else//只有右孩子或者没有孩子
	{
		child = cur->_right;
	}

	if (pnode == nullptr) // 根节点要删除的情况
		_root = child;
	else if (pnode->_left == cur) // 要删除的节点是父节点的左子节点
		pnode->_left = child;
	else // 要删除的节点是父节点的右子节点
		pnode->_right = child;
	delete cur;
	return true;
}

(4)"中序"遍历

学过二叉树的友友,对于这个,没啥好说的吧.

补充小技巧.

由于我们在类外面调用中序遍历函数需要传递root结点,但是root结点是私有成员变量,在类外面无法获取.
对象名.InOrder();

优秀的解决方法:
再嵌套一层,类里面的函数可以直接获取私有成员变量root,所以我们可以利用这一点.

template<class K, class V>
void  BSTree<K, V>::InOrder()
{
	if (_root == nullptr)
	{
		cout << "空树" << endl;
		return;
	}
	_InOrder(_root);		//这里调用即可
}

类中:

template<class K, class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;
public:

	void _InOrder(Node* root);
	void InOrder();
private:
	Node* _root = nullptr;
};

真正的中序遍历:


template<class K, class V>
void  BSTree<K, V>::_InOrder(Node* root)
{
	if (root == nullptr)return;
	_InOrder(root->_left);
	cout << root->_key << "->" << root->_value << endl;
	_InOrder(root->_right);
}

三、结语

好的,到这里二叉搜索树就实现完毕了,二叉搜索树可是很优秀的一种数据结构呢!
搜索数据的时间复杂度在O(logn)级别,因为每判断一次,就可以舍去一半的子树(大往右子树找,小往左子树找),这样就是高度层.

当然,搜索二叉树也是有明显的缺点的,到时候我们在AVL树中介绍吧!

在这里插入图片描述

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

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

相关文章

内容输入.type

内容输入.type 查看完整说明 语法 .type(text) .type(text, options)正确用法 cy.get(input).type(Hello, World) // Type Hello, World into the input错误用法 cy.type(Welcome) // Errors, cannot be chained off cy cy.clock().type(www.cypress.io) // Errors, clock…

新手做抖店,这6点建议一定要收好,能让你不亏钱!

我是电商珠珠 我呢&#xff0c;目前身居郑州。 电商这个行业也做了5年多了&#xff0c;抖店从20年开始做&#xff0c;到现在也已经快3年了。 其实&#xff0c;我做抖店期间呢&#xff0c;踩过很多坑&#xff0c;所以今天就把我所踩过的坑&#xff0c;给做抖店的新手总结了6点…

Latex数学符号查表

摘抄自“《一份&#xff08;不太&#xff09;简短的 LATEX 2ε 介绍》”&#xff0c;来自该网站http://mirrors.cqu.edu.cn/CTAN/info/lshort/chinese/lshort-zh-cn.pdf

VR全景航拍要注意什么,航拍图片如何处理

引言: VR全景航拍技术是当前摄影和航拍领域的新潮流。它采用虚拟现实技术&#xff0c;通过360度全景镜头捕捉画面&#xff0c;可以为观众提供身临其境的视觉体验。在宣传展示中&#xff0c;利用VR全景航拍技术可以为品牌宣传带来更加生动、震撼的视觉效果。 一、航拍注意事项 …

浅谈建筑能耗智能监测平台发展现状及未来趋势

安科瑞 华楠 摘要&#xff1a;文章以每年发布的上海市国家机关办公建筑和大型公共建筑能耗监测及分析报告变化为切入点&#xff0c;分析了历年能耗分析报告的内容和功能变化&#xff1b;介绍了上海市国家机关办公建筑和大型公共建筑能耗监测平台发展和应用历程&#xff1b;揭示…

在 VSCode 中使用 GDB 进行 C/C++ 程序调试(图文版)

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…

steam游戏找不到steam_api64.dll,分享三个有效的解决方法

在现代科技发展的时代&#xff0c;游戏已经成为了许多人生活中不可或缺的一部分。而Steam作为全球最大的数字发行平台之一&#xff0c;拥有着庞大的游戏库和活跃的用户群体。然而&#xff0c;在使用Steam时&#xff0c;有些用户可能会遇到Steam_api64.dll丢失的问题&#xff0c…

一般人用 Linux 算是找虐吗?

一般人用 Linux 算是找虐吗&#xff1f; 主要得看用什么Linux&#xff0c;毕竟Android也算是Linux&#xff0c;满大街一般人整天在用&#xff0c;也没什么人觉得自己在找虐。 最近很多小伙伴找我&#xff0c;说想要一些Linux的资料&#xff0c;然后我根据自己从业十年经验&…

实现点击一个选框 使得一个组件的可选性修改

实现效果 代码 html <div class"divrow"><el-checkbox-group v-model"isSendTag" :max"1"><el-checkbox v-for"(item, index) in isSendTagOptions" :key"index" :label"item.value">{{item.…

实时数据备份实践inotify和rsync联动

目录 一、实时数据备份 1.实时数据备份 2.定时任务周期性的数据备份 3.实时数据备份 4.Inotify机制 二、实践 1.实时复制环境准备 2.实时复制概念 3.InofityRsync实施复制实战 4.配置好rsync守护进程 5.检查linux是否支持inotify 6.安装inotyify--tools 7.inotify…

黑马React: Redux

黑马React: Redux Date: November 19, 2023 Sum: Redux基础、Redux工具、调试、美团案例 Redux介绍 Redux 是React最常用的集中状态管理工具&#xff0c;类似于Vue中的Pinia&#xff08;Vuex&#xff09;&#xff0c;可以独立于框架运行 作用&#xff1a;通过集中管理的方式管…

nodejs搭建本地服务

前端开发时想自己有个本地服务如下操作直接上干货 1.在桌面上直接在powerShell 输入命令行 npm install -g express-generator 然后 npm install -g express 然后新建一个例如server的文件夹 在powerShell执行 express myStudy -e 端口号默认是3000 直接在地址栏输入 http://…

京东数据分析平台(京东运营数据采集):2023年10月京东白酒品牌销售排行榜

鲸参谋监测的京东平台10月份白酒市场销售数据已出炉&#xff01; 鲸参谋数据显示&#xff0c;10月份&#xff0c;京东平台上白酒的销量为340万&#xff0c;环比增长约16%&#xff0c;同比增长约37%&#xff1b;销售额为28亿&#xff0c;环比增长约20%&#xff0c;同比增长约122…

【STM32外设系列】JW01三合一空气质量检测模块

&#x1f380; 文章作者&#xff1a;二土电子 &#x1f338; 关注公众号获取更多资料&#xff01; &#x1f438; 期待大家一起学习交流&#xff01; 文章目录 一、JW01模块简介二、数据格式介绍三、程序设计3.1 串口初始化3.2 串口接收中断服务函数3.3 数据解析函数 四、其他…

全面的日志监控管理工具

企业网络由众多日志源组成。集中监控这些日志源有助于防止数据威胁和网络攻击&#xff0c;综合日志监控解决方案可以自动执行日志管理流程&#xff0c;通过关联日志来识别恶意活动&#xff0c;并帮助满足IT合规性要求。 不同类型的日志监控 EventLog Analyzer 综合日志监控解…

Mysql数据库 17.Mysql存储引擎

Mysql体系结构分为4层&#xff1a; 1.连接层 最上层是一些客户端和连接服务&#xff0c;包括大多数基于客户端/服务端工具实现的类似于TCP/IP的通信&#xff0c;主要功能是完成一些类似于连接处理、授权认证、安全方案等&#xff0c;在该层上还引入线程池的概念&#xff0c;为…

免费图书教材配套资料:Spark大数据技术与应用(第2版)

《Spark大数据技术与应用&#xff08;第2版&#xff09;》课程内容全面介绍了Spark大数据技术的相关知识&#xff0c;内容包含包括Spark概述、Scala基础、Spark编程、Spark编程进阶、Spark SQL结构化数据文件处理、Spark Streaming实时计算框架、Spark GraphX图计算框架、Spark…

电商平台API接口的作用到底是什么?重要性又是什么?具体接入方式?

电商平台API接口的重要性及其作用主要体现在以下几个方面&#xff1a; 数据支持&#xff1a;电商平台拥有大量的商品信息、用户信息、交易信息等大数据资产&#xff0c;而API接口提供访问这些数据的途径&#xff0c;使得其他软件、应用、网站等可以利用这些数据提供更丰富的功…

priority_queue简单实现(优先级队列)(c++)

priority_queue priority_queue介绍逻辑实现框架调整算法adjust_up()adjust_down() 仿函数/比较函数仿函数特性 构造函数迭代器区间构造 完整优先级队列代码 priority_queue介绍 pri_que是一个容器适配器&#xff0c;它的底层是其他容器&#xff0c;并由这些容器再封装而来。类…

PCB抄板的一些方法

PCB抄板的技术实现过程简单来说&#xff0c;就是先将要抄板的电路板进行扫描&#xff0c;记录详细的元器件位置&#xff0c;然后将元器件拆下来做成物料清单&#xff08;BOM&#xff09;并安排物料采购&#xff0c;空板则扫描成图片经抄板软件处理还原成pcb板图文件&#xff0c…