Binary Search Tree

这篇博客要说的是二叉搜索树,又叫二叉排序树,它或者是一颗空树,或者是具有以下性质的二叉树:

·若它的左子树不为空,那么左子树上所有节点的值都小于根节点的值,不会出现等于的情况

·若它的右子树不为空,那么右子树上所有节点的值都大于根节点的值,不会出现等于的情况

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

我们可以由上边的特点推断出二叉树的中序遍历是有序的,比如给一个二叉搜索树

中序遍历就是7 15 17 22 27 30 45 60 75这是有序的。

知道了它的这些特性,那么我们来自己来模拟实现一下:

我们首先需要一个节点的类

然后我们写一个查找函数,就是根据我们上边的规则进行查找

下面我们写一个插入元素的函数,我们在插入的时候,一味的找底为空是不行的,我们需要记录下它的父亲的节点才可以

此时我们就可以创建一个二叉搜索树,那么我按中序遍历试一试,究竟是不是有序的呢?我们就写一个中序遍历的打印函数,我们在调用函数的时候是不需要传值的,而递归打印又需要根节点的值,所以我们封装一层

下面就是我们删除节点的函数,删除的节点有三种情况,没有孩子,有一个孩子和有两个孩子。其中没有孩子和有一个孩子可以一起处理,就是有两个孩子的比较难处理,我们选择用替换法:就是用左子树中最大节点或右子树中最小节点去替换掉我们要删除的值。大家可以想一想为什么,因为我这样替换并不影响搜索二叉树的性质。由于代码比较长,我们放在文章的最后

下面我们来递归实现以下查找和插入函数,跟我们的打印一样,我们要实现递归就要封装一层,我们先来实现简单的插入和查找

注意了:_insertR这里第一个参数我们用的引用,如果不用引用的话,那么root就只是一个拷贝,并不会对实际的二叉树产生影响。下面是删除函数的递归形式

那如果我们想用一棵二叉树生成另一颗二叉树,我们就要写拷贝构造,因为默认生成的是浅拷贝,以及后面一系列的析构和赋值重载

上面就是我们的类的一系列函数下面有两个模型,一个叫key模型,一个叫keyvalue模型,key搜索模型就是快速查找一个值是否存在,比如我们的门禁系统,小区车库都是根据你的信息,去系统中查找这个值是否存在。keyvalue模型是通过一个值去查找另一个值是否存在,比如说:商场车库,通过车牌号去查找你的停车时间,比如手机上的词典软件,高铁站刷票系统,通过你的信息去查找这辆列车有没有你的信息。

下面是所有的代码

template<class K>
struct BSTreeNode {
	BSTreeNode(const K& key)
		:left(nullptr)
		,right(nullptr)
		,_key(key){}
	BSTreeNode(){}
	BSTreeNode* left=nullptr;
	BSTreeNode* right=nullptr;
	K _key=K();
};

template<class K>
class BSTree {
	typedef BSTreeNode<K> Node;
public:
	bool find(const K& key) {
		if (_root == nullptr) {
			return false;
		}
		Node* cur = _root;
		while (cur != nullptr) {
			if (cur->_key < key)cur = cur->right;
			else if (cur->_key > key)cur = cur->left;
			else return true;
		}
		return false;
	}
	bool insert(const K& key) {
		Node* tmp = new Node(key);
		//tmp->_key = key;
		if (_root == nullptr) {
			_root = tmp;
			return true;
		}
		else {
			Node* cur = _root;
			Node* parent = _root;
			while (cur != nullptr) {
				if (cur->_key < key) {
					parent = cur;
					cur = cur->right;
				}
				else if (cur->_key > key) {
					parent = cur;
					cur = cur->left;
				}
				else return false;
			}
			if (parent->_key < key)parent->right = tmp;
			else if (parent->_key > key)parent->left = tmp;
			return true;
		}
	}
	bool erase(const K& key) {
		if (_root == nullptr)return false;
		else {
			Node* cur = _root;
			Node* parent = _root;
			while (cur != nullptr) {
				if (cur->_key < key) {
					parent = cur;
					cur = cur->right;
				}
				else if (cur->_key > key) {
					parent = cur;
					cur = cur->left;
				}
				else {
						if (cur->left == nullptr) {
							if (parent->left == cur) {
								parent->left = cur->right;
							}
							else if (parent->right == cur) {
								parent->right = cur->right;
							}
							else {
								Node* tmp = _root;
								_root = _root->right;
							}
							delete cur;
							return true;
						}
						else if(cur->right==nullptr) {
							if (parent->left == cur) {
								parent->left = cur->left;
							}
							else if (parent->right == cur) {
								parent->right = cur->left;
							}
							else {
								Node* tmp = _root;
								_root = _root->left;
							}
							delete cur;
							return true;
						}
					else {
						Node* leftreemax = cur->left;
						Node* leftreemaxpa = cur;
						while (leftreemax->right != nullptr) {
							leftreemaxpa = leftreemax;
							leftreemax = leftreemax->right;
						}
						cur->_key = leftreemax->_key;
						leftreemaxpa->left = leftreemax->left;
						delete leftreemax;
						return true;
					}
				}
			}
			return false;
		}
	}
								
	

	void PrintBSTree() {
		_PrintBSTree(_root);
		cout << endl;
	}
	bool findR(const K& key) {
		return _findR(_root, key);
	}
	bool insertR(const K& key) {
		return _insertR(_root, key);
	}
	bool eraseR(const K& key) {
		return _eraseR(_root, key);
	}
	~BSTree() {
		Destroy(_root);
	}
	BSTree() = default;//强制生成默认构造
	BSTree(const BSTree<K>& t) {
		_root=copy(t._root);
	}
	BSTree<K>& operator=(BSTree<K> t)
	{
		swap(_root, t._root);
		return *this;
	}
private:
	Node* copy(Node* root) {
		if (root == nullptr)return nullptr;
		Node* newnode = new Node(root->_key);
		newnode->left = copy(root->left);
		newnode->right = copy(root->right);
		return newnode;
	}

	void Destroy(Node* root) {
		if (root == nullptr)return;
		Destroy(root->left);
		Destroy(root->right);
		delete root;
	}

	bool _eraseR(Node*& root, const K& key) {
		if (root == nullptr)return false;
		if (root->_key < key) {
			return _eraseR(root->right, key);
		}
		else if (root->_key > key) {
			return _eraseR(root->left, key);
		}
		else {
			if (root->left == nullptr) {
				Node* tmp = root;
				root = root->right;
				delete tmp;
				return true;
			}
			else if (root->right == nullptr) {
				Node* tmp = root;
				root = root->left;
				delete tmp;
				return true;
			}
			else {
				Node* leftreemaxpa = root;
				Node* leftreemax = root->left;
				while (leftreemax->right != nullptr) {
					leftreemaxpa = leftreemax;
					leftreemax = leftreemax->right;
					}
					swap(root->_key, leftreemax->_key);
					return _eraseR(root->left, key);
					/*root->_key = leftreemax->_key;
					if (leftreemax == leftreemaxpa->left)leftreemaxpa->left = leftreemax->left;
					else leftreemaxpa->right = leftreemax->left;
					delete leftreemax;
					return true;*/
				}
			}
		}
	

	bool _insertR(Node*& root, const K& key) {
		if (root == nullptr) {
			root = new Node(key);
			return true;
		}
		if (root->_key < key) {
			return _insertR(root->right, key);
		}
		else if (root->_key > key) {
			return _insertR(root->left, key);
		}
		else return false;
	}

	bool _findR(Node* root, const K& key) {
		if (root == nullptr)return false;
		if (root->_key == key)return true;
		else if (root->_key < key)return _findR(root->right, key);
		else return _findR(root->left, key);
	}

	void _PrintBSTree(Node* root) {
		if (root == nullptr) return;
		_PrintBSTree(root->left);
		cout << root->_key << ' ';
		_PrintBSTree(root->right);
	}
	Node* _root=nullptr;
};

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

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

相关文章

树状数组(概念 + 模板 + 例题)

1 . 概念 修改 &#xff0c; 就是从前往后修 &#xff0c; 查寻&#xff0c;就是从后往前查&#xff0c;然后累加 ; 2 . 模板 : #define lowbit(x) (x&(-x)) // 获取最后一个1 const int N 5e510;int n , m , s[N] ; // 向后修 void change(int x , int k){while(x&l…

全自动引流,每日500+粉丝的秘诀

在如今竞争激烈的市场环境下&#xff0c;如何有效地吸引和保持精准粉丝成为了每个企业主或网红必须面对的问题。然而&#xff0c;许多人可能误以为全自动引流就意味着无人参与&#xff0c;实际上&#xff0c;它更多的是借助一些自动化工具和策略来提升我们的工作效率。今天&…

代码随想录 图论

目录 797.所有可能得路径 200.岛屿数量 695.岛屿的最大面积 1020.飞地的数量 130.被围绕的区域 417.太平洋大西洋水流问题 827.最大人工岛 127.单词接龙 841.钥匙和房间 463.岛屿的周长 797.所有可能得路径 797. 所有可能的路径 中等 给你一个有 n 个节点的…

java项目通用Dockerfile

创建Dockerfile文件&#xff0c;放到项目根目录下和pom.xml同级别 仅需修改为自己项目端口号即可&#xff0c;其他的无需改动 FROM openjdk:11.0.11-jre-slimCOPY target/*.jar .EXPOSE 8080ENTRYPOINT java -jar *.jar构建语句(注意末尾的点 . ) docker build -t container…

GIS+Python:地质灾害风险评价的智能化解决方案

地质灾害是指全球地壳自然地质演化过程中&#xff0c;由于地球内动力、外动力或者人为地质动力作用下导致的自然地质和人类的自然灾害突发事件。由于降水、地震等自然作用下&#xff0c;地质灾害在世界范围内频繁发生。我国除滑坡灾害外&#xff0c;还包括崩塌、泥石流、地面沉…

后端常见面经之MySQL

MySQL字段类型 数值类型 整型经常被用到&#xff0c;比如 tinyint、int、bigint 。默认是有符号的&#xff0c;若只需存储无符号值&#xff0c;可增加 unsigned 属性。 int(M)中的 M 代表最大显示宽度&#xff0c;并不是说 int(1) 就不能存储数值10了&#xff0c;不管设定了显…

17:00面试,17:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

如何用二维码分享视频?视频转二维码在电脑生成的方法

现在很多的视频都会通过生成二维码的方式来完成分享&#xff0c;在手机上通过扫码预览内容更符合现在人群的行为习惯&#xff0c;从而提升用户获取内容的效率及用户体验。而且这种方式的应用对于制作者而言也可以通过更快的方法来完成视频分享&#xff0c;有效的降低自身需要花…

缺省和重载。引用——初识c++

. 个人主页&#xff1a;晓风飞 专栏&#xff1a;数据结构|Linux|C语言 路漫漫其修远兮&#xff0c;吾将上下而求索 文章目录 C输入&输出cout 和cin<<>> 缺省参数全缺省半缺省应用场景声明和定义分离的情况 函数重载1.参数的类型不同2.参数的个数不同3.参数的顺…

刷题记录:最长公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow","flight"] 输出&#xff1a;"fl"示例 2&#xff1a; 输…

慧天[HTWATER]软件:最好用的城市排水,数据处理软件

【城市内涝水文水动力模型介绍】 慧天[HTWATER]软件&#xff1a;慧天排水数字化分析平台针对城市排水系统基础设施数据管理的需求&#xff0c;以及水文、水力及水质模拟对数据的需求&#xff0c;实现了以数据库方式对相应数据的存储。可以对分流制排水系统及合流制排水系统进行…

如何让企微助手加粉更精准?

在当今数字化营销时代&#xff0c;无论是抖音平台上的广告投放&#xff0c;还是微信朋友圈的推广&#xff0c;其目的均是为了提升品牌曝光度和产品展示度。然而&#xff0c;更重要的是&#xff0c;广告的目的在于吸引潜在的目标客户&#xff0c;进而实现转化。在这个过程中&…

SHA加密

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

20240319-1-过拟合与欠拟合

过拟合欠拟合面试题 1. 如何理解高方差与低偏差? 模型的预测误差可以分解为三个部分: 偏差(bias)&#xff0c; 方差(variance) 和噪声(noise). 偏差 偏差度量了模型的期望预测与真实结果的偏离程度&#xff0c; 即刻画了学习算法本身的拟合能力。偏差则表现为在特定分布上…

Git基础(25):Cherry Pick合并指定commit id的提交

文章目录 前言指定commit id合并使用TortoiseGit执行cherry-pick命令 前言 开发中&#xff0c;我们会存在多个分支开发的情况&#xff0c;比如dev&#xff0c;test, prod分支&#xff0c;dev分支在开发新功能&#xff0c;prod作为生产分支已发布。如果某个时候&#xff0c;我们…

【MySQL】10. 复合查询(重点)

复合查询&#xff08;重点&#xff09; 前面我们讲解的mysql表的查询都是对一张表进行查询&#xff0c;在实际开发中这远远不够。 1. 基本查询回顾 数据还是使用之前的雇员信息表 在标题7的位置&#xff01; mysql> select * from emp where sal > 500 or job MANAG…

Unity数独完整源码

支持的Unity版本&#xff1a;2018.1或更高。 这是一套完整且高效的数独源码&#xff0c;默认是9x9&#xff0c;有上千种关卡文件&#xff0c;4种难度&#xff0c;内有关卡编辑器&#xff0c;可扩展至4x4、6x6的关卡&#xff0c;还有英文文档对源码各方面可配置的地方进行说明&…

静态住宅IP好用吗?怎么选择?

在进行海外 IP 代理时&#xff0c;了解动态住宅 IP 和静态住宅 IP 的区别以及如何选择合适的类型非常重要。本文将介绍精态住宅 IP 特点和&#xff0c;并提供选择建议&#xff0c;帮助您根据需求做出明智的决策。 静态住宅 IP 的特点 静态住宅 IP 是指 IP 地址在一段时间内保…

冒泡排序 快速排序 归并排序 其他排序

书接上回.. 目录 2.3 交换排序 2.3.1冒泡排序 2.3.2 快速排序 快速排序的优化: 快速排序非递归 2.4 归并排序 基本思想 归并排序非递归 海量数据的排序问题 排序算法时间空间复杂度和稳定性总结 四. 其他非基于比较排序 (了解) 2.3 交换排序 基本思想&#xff1a;…

GIS、CAD数据为基础进行城市排水系统水力建模方法

佳文推荐 城市内涝水文水动力模型介绍 在城市排水防涝规划过程中&#xff0c;水文水动力耦合模型已经成为一种不可或缺的分析工具。在模型建立、城市内涝风险评估、排水系统性能诊断以及海绵城市规划等方面&#xff0c;内涝耦合模型提供了相应的模拟及分析工具&#xff1a; …