<C++>手撕搜索二叉树

news2024/11/26 16:46:03

目录

一、搜索二叉树的性质

二、搜索二叉树的结构定义

三、手撕搜索二叉树非递归

1)Insert()

2)Find()

3)Erase()

4)InOder()

5)BSTree(const BSTree& t) 拷贝构造

6)~BSTree()析构函数

四、手撕搜索二叉树递归

1)InsertR()

2)FindR()

3)EraseR()

五、搜索二叉树完整代码


一、搜索二叉树的性质

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

二、搜索二叉树的结构定义

搜索二叉树主要实现的是K或K/Value模型,这里我们使用K模型来定义,即可以用O(N)的时间复杂度来进行K值的搜索。

 

使用模板来定义

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

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

	}
};

三、手撕搜索二叉树非递归

1)Insert()

插入有两种情况:

  • _root == nullptr 根节点等于空

直接new a Node插入即可

if (_root == nullptr)
{
	_root = new Node(key);
	return true;
}
  • _root != nullptr 根节点不等于空

我们需要找到适合key值的空节点位置,通过搜索二叉树的性质进行排查位置

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}

			//开始插入
			cur = new Node(key);
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}

 

 

 

2)Find()

直接通过搜索二叉树的性质就可以进行查找,当key值大于cur->_key的值时,就查找cur的右子树,key值小于cur->_key的值时,就查找cur的左子树,直到找到,或者找不到cur == nullptr结束,即逻辑和Inser中的逻辑大同小异;

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

3)Erase()

删除分三种情况:

  • 删除节点没有孩子
  • 删除节点有一个孩子
  1. 有一个左孩子
  2. 有一个右孩子
  • 删除节点有两个孩子

前面两种代码可以合并处理

	bool Erase(const K& key)
	{
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			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 (cur == _root)
					{
						_root = cur->_right;
					}
					else
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}

					delete cur;
					cur = nullptr;
				}
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
					}

					delete cur;
					cur = nullptr;
				}
				else
				{
					Node* minParent = cur;
					Node* min = cur->_right;
					while (min->_left)
					{
						minParent = min;
						min = min->_left;
					}

					swap(cur->_key, min->_key);

					if (minParent->_left == min)
					{
						minParent->_left = min->_right;
					}
					else
					{
						minParent->_right = min->_right;
					}

					delete min;
					min = nullptr;
				}

				return true;
			}
		}

		return false;
	}

4)InOder()

使用二叉树的中序遍历--midorder traverse

特点:

中序遍历后的值排列是有序的

    void InOrder()
    {
		_InOrder(_root);
		return;
    }

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

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

5)BSTree(const BSTree<K>& t) 拷贝构造

使用前序遍历构造


	BSTree(const BSTree<K>& t)
	{
		_Copy(t._root);
	}

    Node* _Copy(Node* root) // 使用前序遍历构造
	{
		if (root == nullptr)
		{
			return;
		}

		Node* copyRoot = new Node(root->_key);
		copyRoot->_left = _Copy(root->_left);
		copyRoot->_left = _Copy(root->_right);
		return copyRoot;
	}

6)~BSTree()析构函数

使用后序销毁

	~BSTree()
	{
		_Destory(_root);
	}

    void _Destory(Node* root) // 使用后序销毁
	{
		if (root == nullptr)
		{
			return;
		}

		_Destory(root->_left);
		_Destory(root->_right);
		delete root;
		root = nullptr;
	}

四、手撕搜索二叉树递归

1)InsertR()

	bool InertR(const K& key)
	{
		return _InsertR(_root, key);
	}
    
    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;
		}
	}

2)FindR()

    bool FindR(const K& key)
	{
		return _FindR(_root, key);
	}

    bool _FindR(Node* root, const K& key)
	{
		if (root == nullptr)
		{
			return false;
		}

		if (root->_key < key)
		{
			return _FindR(root->_right);
		}
		else if (root->_key > key)
		{
			return _FindR(root->_left);
		}
		else
		{
			return true;
		}
	}

3)EraseR()

    bool EraseR(const K& key)
	{
		return _EraseR(_root, key);
	}

    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
		{
			Node* del = root;
			if (root->_left == nullptr)
			{
				root = root->_right;
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else
			{
				//找右数的最左节点
				Node* min = root->_right;
				while (min->_left)
				{
					min = min->_left;
				}

				swap(root->_key, min->_key);
				return _InserR(root->_right, key);
			}

			delete del;
			return true;
		}
	}

五、搜索二叉树完整代码

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 BSTree
{
	typedef BSTreeNode<K> Node;
public:
	bool Insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}
		else
		{
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}

			//开始插入
			cur = new Node(key);
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}
		}

	}

	void InOrder()
	{
		_InOrder(_root);
		return;
	}

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

		return false;
	}

	bool Erase(const K& key)
	{
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			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 (cur == _root)
					{
						_root = cur->_right;
					}
					else
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}

					delete cur;
					cur = nullptr;
				}
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_left;
						}
						else
						{
							parent->_right = cur->_left;
						}
					}

					delete cur;
					cur = nullptr;
				}
				else
				{
					Node* minParent = cur;
					Node* min = cur->_right;
					while (min->_left)
					{
						minparnt = min;
						min = min->_left;
					}

					swap(cur->_key, min->_key);

					if (minParent->_left == min)
					{
						minParent->_left = min->_right;
					}
					else
					{
						minParent->_right = min->_right;
					}

					delete min;
					min = nullptr;
				}

				return true;
			}
		}

		return false;
	}

	BSTree() = default;

	BSTree(const BSTree<K>& t)
	{
		_Copy(t._root);
	}

	~BSTree()
	{
		_Destory(_root);
	}


//
	bool FindR(const K& key)
	{
		return _FindR(_root, key);
	}

	bool InertR(const K& key)
	{
		return _InsertR(_root, key);
	}

	bool EraseR(const K& key)
	{
		return _EraseR(_root, key);
	}


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

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

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

		_Destory(root->_left);
		_Destory(root->_right);
		delete root;
		root = nullptr;
	}

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

		Node* copyRoot = new Node(root->_key);
		copyRoot->_left = _Copy(root->_left);
		copyRoot->_left = _Copy(root->_right);
		return copyRoot;
	}

	bool _FindR(Node* root, const K& key)
	{
		if (root == nullptr)
		{
			return false;
		}

		if (root->_key < key)
		{
			return _FindR(root->_right);
		}
		else if (root->_key > key)
		{
			return _FindR(root->_left);
		}
		else
		{
			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 _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
		{
			Node* del = root;
			if (root->_left == nullptr)
			{
				root = root->_right;
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else
			{
				//找右数的最左节点
				Node* min = root->_right;
				while (min->_left)
				{
					min = min->_left;
				}

				swap(root->_key, min->_key);
				return _InserR(root->_right, key);
			}

			delete del;
			return true;
		}
	}

private:
	Node* _root = nullptr;
};

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

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

相关文章

【学习笔记65】JavaScript的继承

一、认识继承 function Person(name) {this.name name}Person.prototype.sayName () > {console.log(name)}function Stu(age) {this.age age}const s new Stu(18)console.log(s) // {age: 18} 说明&#xff1a; 想让s这个对象内部有一个name属性, 并且可以使用 sayN…

双功能连接试剂:Alkyne hydrazide,炔烃-酰肼 主要特点进行分享

Alkyne hydrazide物理参数&#xff1a; CAS号&#xff1a;N/A |英文名&#xff1a;Alkyne hydrazide | 中文名&#xff1a;炔烃-酰肼 货号&#xff1a;X-CL-1132 分子式&#xff1a;C6H11ClN2O 分子量&#xff1a;162.62 纯度&#xff1a;95% 外形&#xff1a;淡黄色或白…

企业级的商用远程控制软件有哪些

现在远程控制软件&#xff0c;可选性还是比较大的。针对个人用户市场&#xff0c;也有不少免费软件。 企业用户的需求和个人用户的需求&#xff0c;差别较大。个人用户市场&#xff0c;主要诉求是免费、好用。企业用户&#xff0c;主要关注安全、管理功能、性能、价格等因素。…

为什么建议MySQL在2000W条左右记录分表

为什么建议MySQL在2000W条左右记录分表&#xff1f;这个数量问题并不是绝对的&#xff0c;这是一个相对的数量。在回答这个问题前我们应该先了解MySQL底层是用的什么数据结构来进行数据存储的。 MySQL底层采用的B树进行的数据存储 InnoDB存储引擎最小储存单元是页&#xff0c;…

【Java面试】异常常见面试题

文章目录1. Error 和 Exception 区别是什么&#xff1f;运行时异常和一般异常(受检异常)区别是什么&#xff1f;JVM 是如何处理异常的&#xff1f;throw 和 throws 的区别是什么&#xff1f;final、finally、finalize 有什么区别&#xff1f;NoClassDefFoundError 和 ClassNotF…

OpenMP 快速入门

学习《高性能计算&#xff1a;现代系统与应用实践》&#xff08;Thomas Sterling&#xff0c;Matthew Anderson&#xff0c;Maciej Brodowicz&#xff09;第 7 章 OpenMP 的基础 OpenMP OpenMP 是一个 API C、C、Fortran OpenMP 是共享内存的多线程编程模型 共享内存 默认所有…

22年11月-自研-面试题

目录背景题目Activiti回退功能条件分支功能&#xff0c;并行网关、包含网关有没有用到流程流转中&#xff0c;需知会其他人&#xff0c;这些人需同意/做处理&#xff08;有点流程的感觉&#xff09;&#xff0c;最后所有的意见都要汇总。你的实现思路Redis哪些数据结构&#xf…

STM32实战总结:HAL之低功耗

低功耗的含义不必过多解释&#xff0c;一听就能懂。 低功耗对电池供电产品尤其重要。 STM32的有三种低功耗模式&#xff0c;即睡眠模式、停止模式和待机模式。 在我的印象中&#xff0c;停止不就是关机吗&#xff1f;但并不是。 在系统或电源复位以后&#xff0c;微控制器处于运…

基于最小二乘插值(Least-Squares Interpolation)图像超分辨率重构算法研究-附Matlab代码

⭕⭕ 目 录 ⭕⭕✳️ 一、引言✳️ 二、最小二乘图像插值理论与Matlab处理✳️ 三、基于最小二乘插值超分辨重构实验验证✳️ 四、参考文献✳️ 五、Matlab程序获取与验证✳️ 一、引言 图像超分辨率重构技术起源于上世纪60年代Harris和Goodman构造的单帧图像重构方法&#xf…

AutoCAD Electrical 2022—元件的绘制

原理图——图标菜单 选择要插入的元件&#xff1b; 根据实际情况&#xff0c;选择垂直放置还是水平放置&#xff0c;比例大小&#xff1b; 选择一个三极断路器&#xff0c;垂直放置&#xff1b; 点击确定后&#xff0c;点击一根导线&#xff0c;选择断路器另外两个符号是的方向…

相控阵天线(十一):阵列天线有源驻波分析

目录简介有源驻波概念和计算公式平面阵列天线的有源驻波平面阵列有源驻波计算公式平面阵列有源驻波仿真示例不同耦合系数/隔离度的有源驻波分析简介 有源相控阵最大的特点是每一个收发天线后均连接一个独立的T/R组件&#xff0c;每一个T/R组件相当于一个常规雷达的高频前端&am…

【信息检索与数据挖掘期末笔记】(二) IR Evaluation

文章目录测试集无序检索结果集合的评价Precision & RecallAccuarcy?F值有序检索结果评价方法二值相关&#xff08;相关/不相关&#xff09;PrecisionK&#xff08;PK&#xff09;Mean Average Precision&#xff08;MAP&#xff09;Mean Reciprocal Rank多级相关CG&#x…

LeetCode542. 01 矩阵(C++中等题)

题目 给定一个由 0 和 1 组成的矩阵 mat &#xff0c;请输出一个大小相同的矩阵&#xff0c;其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 示例 1&#xff1a; 输入&#xff1a;mat [[0,0,0],[0,1,0],[0,0,0]] 输出&#xff1a;[[…

(三) 共享模型之管程【共享带来的问题】

一、共享带来的问题 1. 临界区 &#xff08;1&#xff09;一个程序运行多个线程本身是没有问题的 &#xff08;2&#xff09;问题出在多个线程访问共享资源 1️⃣多个线程读共享资源其实也没有问题 2️⃣在多个线程对共享资源读写操作时发送指令交错&#xff0c;就会出现问题 …

git@github.com: Permission denied (publickey).

本地虚拟机ubuntu上安装git&#xff0c;想从github上拉取项目到ubuntu上的过程。 1、在ubuntu上安装git 更新apt指令 sudo apt update 安装git sudo apt install git 查看安装git版本 git --version 2、ssh认证 首先已经安装了ssh指令 先执行 ssh -T gitgithub.com 执行之…

3.11 怎么增加小红书评论区的互动?【玩赚小红书】

今天就为大家总结了一下&#xff0c;关于小红书粉丝互动的一些小技巧&#xff0c;来供大家参考。 ​ ​ 一、 固好“真爱粉” 经常会在笔记下面评论、点赞、浏览笔记内容的粉丝&#xff0c;也就是所谓的“真爱粉”、“铁粉”&#xff0c;我们就需要用心维护这一部分粉丝。 ​…

虹科分享|硬件加密U盘|居家办公的网络安全:远程员工可以采取的步骤

新冠肺炎的流行迫使数以百万计的人在家工作&#xff0c;而当时他们对这一概念知之甚少&#xff0c;甚至完全没有经验。虽然许多员工已经重返办公室&#xff0c;但最近的一项研究发现&#xff0c;72%的受访者希望每周至少有两天在家工作&#xff0c;32%的人表示他们希望永久在家…

全波形反演的深度学习方法: 第 4 章 基于正演的 FWI (草稿)

本章论述经典的 FWI, 它基于正演方法. 本贴仅供内部培训. 4.1 FWI 问题 图 4.1 FWI 的输入与输出 [1].图 4.2 FWI 的数学式子.正演问题是建立从速度模型到地震数据的映射. 一般认为是单解的, 即一个速度模型只能生成一个地震数据 (如果不考虑噪声).反演问题是建立从地震数据到…

【题解】E. Sending a Sequence Over the Network(1741)

链接&#xff1a;https://codeforces.com/problemset/problem/1741/E 题目大意 给出一个数组&#xff0c;判断它是否是合法的&#xff0c;如果合法则输出YES&#xff0c;不合法则输出NO。 合法规则&#xff1a;一段序列中&#xff0c;这个序列的第一个或者最后一个的数值&…

岩藻多糖-聚乙二醇-胆固醇Cholesterol-PEG-FucoidanFucoidan-Cholesterol 岩藻多糖-胆固醇

岩藻多糖-聚乙二醇-胆固醇Cholesterol-PEG-FucoidanFucoidan-Cholesterol 岩藻多糖-胆固醇 中文名称&#xff1a;岩藻多糖-胆固醇 英文名称&#xff1a;Fucoidan-Cholesterol 别称&#xff1a;胆固醇修饰岩藻多糖&#xff0c;胆固醇-岩藻多糖 外观:固体或粘性液体&#xff…