[C++]二叉搜索树

news2025/1/21 6:02:40

一、定义

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

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

二、插入insert

对于二叉搜索树的插入操作,我们将需要插入的key值与当前结点(初始结点是root结点)比较,若小于该结点的值,则往左子树走;若大于该结点的值,则往右子树走。走到空结点的时候,那么这个位置就是这个key值的归宿。

template<class K, class V>
struct BSTreeNode
{
	BSTreeNode<K, V>* left;
	BSTreeNode<K, V>* right;

	K _key;
	V _value;
};

template<class K, class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;
public:
	BSTree()
	{
		_root = nullptr;
	}


	bool Insert(const K& key, const V& value)
	{
		if (_root == nullptr)
		{
			_root = new Node;
			_root->_key = key;
			_root->_value = value;
			_root->left = nullptr;
			_root->right = nullptr;
		}
		else
		{
			Node* cur = _root;
			Node* parent = _root;
			while (cur)
			{
				if (key < cur->_key)
				{
					parent = cur;
					cur = cur->left;

				}
				else if (key > cur->_key)
				{
					parent = cur;
					cur = cur->right;
				}
			}
			cur = new Node;
			cur->left = nullptr;
			cur->right = nullptr;
			cur->_key = key;
			cur->_value = value;

			if (key < parent->_key)
			{
				parent->left = cur;
			}
			else
			{
				parent->right = cur;
			}

		}

		return true;
	}
private:


	Node* _root = nullptr;
};

三、查找操作find

对于二叉搜索树的查找操作,我们将需要查找的key值与当前结点(初始结点是root结点)比较,若小于该结点的值,则往左子树走;若大于该结点的值,则往右子树走。

若走到空,则说明没有这个值,返回空指针。若找到该值,则返回该值的结点。

	Node* 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 cur;
			}
		}

		return nullptr;
	}

四、删除操作

	bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = _root;
		while (cur)
		{
			//若key小于当前结点的值,则往左子树走
			if (key < cur->_key)
			{
				parent = cur;
				cur = cur->left;
			}

			//若key大于当前结点的值,则往右子树走
			else if (key > cur->_key)
			{
				parent = cur;
				cur = cur->right;
			}
			//若key值与当前结点的值相等,则说明该结点就是需要删除的
			else
			{
				//该结点左右子树皆为空的情况
				if (cur->left == nullptr && cur->right == nullptr)
				{
					//直接删除
					if (key < parent->_key)
					{
						parent->left = nullptr;
					}
					if (key > parent->_key)
					{
						parent->right = nullptr;
					}

					delete cur;
				}
				//该结点左子树为空的情况
				else if (cur->left == nullptr)
				{
					//将该结点的左子树链接到该结点的父结点的子树上,然后删除该结点
					if (key < parent->_key)
						parent->left = cur->right;
					else
						parent->right = cur->right;
					delete cur;
				}
				//该结点右子树为空的情况
				else if (cur->right == nullptr)
				{
					//将该结点的右子树链接到该结点的父结点的子树上,然后删除该结点
					if (key < parent->_key)
						parent->left = cur->left;
					else
						parent->right = cur->left;
					delete cur;
				}
				//左右子树皆不为空
				//该情况下,我们需要找到左子树的最大结点/右子树的最小结点
				//然后将需要删除的结点的值和找到的最大结点/最小结点的值交换
				//此时我们只需要删除交换之后值为需要删除的数值的结点
				//这里以与左子树的最大结点交换为例
				else
				{
					//del是之后需要删除的结点
					Node* del = cur->left;
					//tmp是需要删除的结点的父结点
					Node* tmp = del;
					//找到左子树的最大结点,记录为del,此时tmp为del的父结点
					while (del->right)
					{
						tmp = del;
						del = del->right;

					}
					//交换key值
					swap(cur->_key, del->_key);

					//如即将被删除的结点有左子树,则将其链接到tmp上
					if (del->left)
					{
						tmp->right = del->left;
					}
					//否则直接将tmp指向即将被删除的结点的指针置空
					else
					{
						tmp->right = nullptr;
					}

					//删除交换key值后的结点
					delete del;
					
				}

				return true;
			}
			
		}

		return false;
	}

五、中序遍历InOrder

使用中序遍历二叉搜索树时,我们得到的是一个递增序列。

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

		_InOrder(root->left);
		cout << root->_key << ' ';
		_InOrder(root->right);
	}


	void InOrder()
	{
		_InOrder(_root);

		cout << endl;
	}

六、完整代码

#include<iostream>
#include<string>



template<class K, class V>
struct BSTreeNode
{
	BSTreeNode<K, V>* left;
	BSTreeNode<K, V>* right;

	K _key;
	V _value;
};

template<class K, class V>
class BSTree
{
	typedef BSTreeNode<K, V> Node;
public:
	BSTree()
	{
		_root = nullptr;
	}


	bool Insert(const K& key, const V& value)
	{
		if (_root == nullptr)
		{
			_root = new Node;
			_root->_key = key;
			_root->_value = value;
			_root->left = nullptr;
			_root->right = nullptr;
		}
		else
		{
			Node* cur = _root;
			Node* parent = _root;
			while (cur)
			{
				if (key < cur->_key)
				{
					parent = cur;
					cur = cur->left;

				}
				else if (key > cur->_key)
				{
					parent = cur;
					cur = cur->right;
				}
			}
			cur = new Node;
			cur->left = nullptr;
			cur->right = nullptr;
			cur->_key = key;
			cur->_value = value;

			if (key < parent->_key)
			{
				parent->left = cur;
			}
			else
			{
				parent->right = cur;
			}

		}

		return true;
	}


	Node* 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 cur;
			}
		}

		return nullptr;
	}



	bool Erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = _root;
		while (cur)
		{
			//若key小于当前结点的值,则往左子树走
			if (key < cur->_key)
			{
				parent = cur;
				cur = cur->left;
			}

			//若key大于当前结点的值,则往右子树走
			else if (key > cur->_key)
			{
				parent = cur;
				cur = cur->right;
			}
			//若key值与当前结点的值相等,则说明该结点就是需要删除的
			else
			{
				//该结点左右子树皆为空的情况
				if (cur->left == nullptr && cur->right == nullptr)
				{
					//直接删除
					if (key < parent->_key)
					{
						parent->left = nullptr;
					}
					if (key > parent->_key)
					{
						parent->right = nullptr;
					}

					delete cur;
				}
				//该结点左子树为空的情况
				else if (cur->left == nullptr)
				{
					//将该结点的左子树链接到该结点的父结点的子树上,然后删除该结点
					if (key < parent->_key)
						parent->left = cur->right;
					else
						parent->right = cur->right;
					delete cur;
				}
				//该结点右子树为空的情况
				else if (cur->right == nullptr)
				{
					//将该结点的右子树链接到该结点的父结点的子树上,然后删除该结点
					if (key < parent->_key)
						parent->left = cur->left;
					else
						parent->right = cur->left;
					delete cur;
				}
				//左右子树皆不为空
				//该情况下,我们需要找到左子树的最大结点/右子树的最小结点
				//然后将需要删除的结点的值和找到的最大结点/最小结点的值交换
				//此时我们只需要删除交换之后值为需要删除的数值的结点
				//这里以与左子树的最大结点交换为例
				else
				{
					//del是之后需要删除的结点
					Node* del = cur->left;
					//tmp是需要删除的结点的父结点
					Node* tmp = del;
					//找到左子树的最大结点,记录为del,此时tmp为del的父结点
					while (del->right)
					{
						tmp = del;
						del = del->right;

					}
					//交换key值
					swap(cur->_key, del->_key);

					//如即将被删除的结点有左子树,则将其链接到tmp上
					if (del->left)
					{
						tmp->right = del->left;
					}
					//否则直接将tmp指向即将被删除的结点的指针置空
					else
					{
						tmp->right = nullptr;
					}

					//删除交换key值后的结点
					delete del;
					
				}

				return true;
			}
			
		}

		return false;
	}


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

		_InOrder(root->left);
		cout << root->_key << ' ';
		_InOrder(root->right);
	}


	void InOrder()
	{
		_InOrder(_root);

		cout << endl;
	}


private:


	Node* _root = nullptr;
};

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

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

相关文章

Java+Vue+MySQL,国产动漫网站全栈升级

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

综合练习

目录 查询每个员工的编号、姓名、职位、基本工资、部门名称、部门位置 确定要使用的数据表 确定已知的关联字段 查询每个员工的编号、姓名、职位、基本工资、工资等级 确定要使用的数据表 确定已知的关联字段 查询每个员工的编号、姓名、职位、基本工资、部门名称、工资…

如何系统地学习Python

建议系统学习Python的途径遵循理论与实践相结合的教学方法。以下是一个分阶段的学习计划&#xff1a; 阶段一&#xff1a;基础知识 理解Python的特点&#xff1a; 认识Python的历史与设计哲学。学习Python的基本语法和运行环境。 安装Python&#xff1a; 学习如何在不同操作系…

NNLM - 神经网络语言模型 | 高效的单词预测工具

本系列将持续更新NLP相关模型与方法&#xff0c;欢迎关注&#xff01; 简介 神经网络语言模型&#xff08;NNLM&#xff09;是一种人工智能模型&#xff0c;用于学习预测词序列中下一个词的概率分布。它是自然语言处理&#xff08;NLP&#xff09;中的一个强大工具&#xff0c;…

从kafka如何保证数据一致性看通常数据一致性设计

一、前言 在数据库系统中有个概念叫事务&#xff0c;事务的作用是为了保证数据的一致性&#xff0c;意思是要么数据成功&#xff0c;要么数据失败&#xff0c;不存在数据操作了一半的情况&#xff0c;这就是数据的一致性。在很多系统或者组件中&#xff0c;很多场景都需要保证…

IO进程线程作业day1

1> 使用fgets统计给定文件的行数 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <unistd.h> int main(int argc, const char *argv[]) {//判断外部输入文件名是否规范if(argc!2){printf("in…

K8S之运用污点、容忍度设置Pod的调度约束

污点、容忍度 污点容忍度 taints 是键值数据&#xff0c;用在节点上&#xff0c;定义污点&#xff1b; tolerations 是键值数据&#xff0c;用在pod上&#xff0c;定义容忍度&#xff0c;能容忍哪些污点。 污点 污点是定义在k8s集群的节点上的键值属性数据&#xff0c;可以决…

ARMv8-AArch64 的异常处理模型详解之异常处理详解(进入异常以及异常路由)

在上篇文章 ARMv8-AArch64 的异常处理模型详解之异常处理概述Handling exceptions中&#xff0c;作者对异常处理整体流程以及相关概念做了梳理。接下来&#xff0c;本文将详细介绍处理器在获取异常、异常处理以及异常返回等过程中都做了哪些工作。 ARMv8-AArch64 的异常处理模型…

批量追踪中通快递

在物流信息的管理中&#xff0c;批量追踪中通快递单号一直是个让人头疼的问题。但有了固乔快递查询助手&#xff0c;这一切都变得轻而易举。 固乔快递查询助手&#xff0c;作为市场上备受好评的快递查询软件&#xff0c;专门针对批量查询需求进行了优化。用户只需将中通快递单号…

鸿蒙生态来了 ,60k 高薪向你招手

最近&#xff0c;各大平台都被华为鸿蒙不断刷屏。原因是在华为秋季发布会上&#xff0c;华为宣布启动鸿蒙原生应用&#xff0c;不再兼容安卓应用。一石激起千层浪&#xff0c;这无疑是IT界的一颗核弹&#xff0c;各大企业和开发者都纷纷开始加入“鸿蒙朋友圈”。 鸿蒙原生应用…

数据分析 — Matplotlib 、Pandas、Seaborn 绘图

目录 一、Matplotlib1、折线图2、柱状图3、水平条形图4、直方图5、散点图6、饼图 二、pandas1、折线图2、柱状图 三、seaborn1、散点图2、箱线图3、直方核密度图4、成对图 一、Matplotlib Matplotlib 是一个用于绘制数据可视化图形的 Python 库。它提供了丰富的绘图工具&#…

Eliminating Domain Bias for Federated Learning in Representation Space【文笔可参考】

文章及作者信息&#xff1a; NIPS2023 Jianqing Zhang 上海交通大学 之前中的NeurIPS23论文刚今天传到arxiv上&#xff0c;这次我把federated learning的每一轮看成是一次bi-directional knowledge transfer过程&#xff0c;提出了一种促进server和client之间bi-direction…

浅析Linux设备驱动:IO端口和IO内存

文章目录 概述IO端口和IO内存的区别 IO资源管理IO资源类型IO端口资源IO内存资源 IO资源分配 IO端口访问IO端口操作函数 IO内存访问IO内存操作函数 相关参考 概述 在计算机系统中&#xff0c;外部设备通常会提供一组寄存器或内存用于处理器配置和访问设备功能。这些寄存器或内存…

MCU电源控制(PWR)与低功耗

目录 一、STM32 的内核和外设电源系统管理&#xff1a; 二、MCU电源监控&#xff1a; 三、三种低功耗模式&#xff1a; 1、睡眠模式&#xff1a; 2、停止模式&#xff1a; 3、待机模式&#xff1a; 一、STM32 的内核和外设电源系统管理&#xff1a; ① 电池备份区域&#…

思迈特再获国家权威认证:代码自主率98.78%

日前&#xff0c;思迈特软件自主研发的商业智能与数据分析软件&#xff08;Smartbi Insight&#xff09;通过中国赛宝实验室&#xff08;工业和信息化部电子第五研究所&#xff09;代码扫描测试&#xff0c;Smartbi Insight V11版本扫描测得代码自主率为98.78%的好成绩&#xf…

原创详解OpenAI Sora是什么?技术先进在哪里?能够带来什么影响?附中英文技术文档

一&#xff1a;Sora是什么 Sora是一个文本到视频的模型&#xff0c;由美国的人工智能研究机构OpenAI开发。Sora可以根据描述性的文本提示&#xff0c;生成高质量的视频&#xff0c;也可以根据已有的视频&#xff0c;向前或向后延伸&#xff0c;生成更长的视频。 Sora的主要功…

【完全二叉树节点数!】【深度优先】【广度优先】Leetcode 222 完全二叉树的节点个数

【完全二叉树】【深度优先】【广度优先】Leetcode 222 完全二叉树的节点个数 :star:解法1 按照完全二叉树解法2 按照普通二叉树&#xff1a;深度优先遍历 后序 左右中解法3 按照普通二叉树&#xff1a;广度优先遍历 层序遍历 ---------------&#x1f388;&#x1f388;题目链接…

【漏洞复现-通达OA】通达OA swfupload_new存在前台SQL注入漏洞

一、漏洞简介 通达OA(Office Anywhere网络智能办公系统)是由北京通达信科科技有限公司自主研发的协同办公自动化软件,是与中国企业管理实践相结合形成的综合管理办公平台。通达OA为各行业不同规模的众多用户提供信息化管理能力,包括流程审批、行政办公、日常事务、数据统计…

~汉诺塔~(C语言)~

引言 汉诺塔&#xff08;Hanoi Tower&#xff09;&#xff0c;又称河内塔&#xff0c;源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子&#xff0c;在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从上面开始按大小顺序重新摆放在…

[计算机网络]深度学习传输层TCP协议

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录专栏&#xff1a;深度学习传输层TCP协议 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 [计算机网络]深度学习传输层TCP协议 前提概括一: TCP协议段格式二:确认应答三:超时重传四:…