首页 > 其他分享 >数据结构——二叉搜索树详解

数据结构——二叉搜索树详解

时间:2024-03-26 12:32:19浏览次数:22  
标签:right cur 二叉 详解 key 数据结构 root 节点 left

一、二叉搜索树定义

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

1.非空左子树上所有节点的值都小于根节点的值

2.非空右子树上所有节点的值都大于根节点的值

3.左右子树也都为二叉搜索树。

如下图所示:

二、二叉搜索树的操作

二叉搜索树结构:

template<class k>
	struct BSTreeNode {
		typedef BSTreeNode<k> Node;
		Node* _left;//左子树指针
		Node* _right;//右子树指针
		k _key;//节点数据
	};

2.1 二叉搜索树的查找

1.从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。

2.最多查找高度次,走到到空,还没找到,这个值不存在。

非递归查找:

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 _FindR(Node* root, const k& key)
		{
			if (root == nullptr)
				return false;

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

2.2 二叉搜索树的插入

插入的具体过程如下:

1. 树为空,则直接新增节点,赋值给root指针。

2. 树不空,按二叉搜索树性质查找插入位置,插入新节点。

插入key值为9的节点,如下图所示:

非递归插入:

bool Insert(const k& key) {
			if (_root == nullptr) {
				_root = new Node(key);
				return true;
			}
			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;//key值已存在
				}
			}
			cur = new Node(key);//以key值开辟节点
			if (parent->_key < key) {//新节点>父亲节点,在父亲的右边
				parent->_right = cur;
			}
			if (parent->_key > key) {//新节点<父亲节点,在父亲的左边
				parent->_left = cur;
			}
			return true;
		}

递归插入:

bool _InsertR(Node*& root, const k& key)
		{//递归查找传参指针的引用,修改原指针,让原指针直接指向当前节点
			if (root == nullptr)//root节点为空,开辟新结点
			{
				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.3 二叉搜索树的删除

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情 况:

1. 要删除的结点无孩子结点 2. 要删除的结点只有左孩子结点 3. 要删除的结点只有右孩子结点 4.要删除的结点有左、右孩子结点

看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程 如下:

1.删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除。

2.删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除。 

3.查找删除结点的右子树的最左节点或者左子树的最右节点(距离删除节点最近,替换后不影响其他节点位置),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除。下面用右子树的最左节点进行替换。

非递归删除:

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->_right)
							{//判断删除节点是parent的left还是right
								parent->_right = cur->_right;
							}
							else
							{
								parent->_left = cur->_right;
							}
						}
						delete cur;
						return true;
					}
					else if (cur->_right == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (cur == parent->_right)
							{//判断删除节点是parent的left还是right
								parent->_right = cur->_left;
							}
							else
							{
								parent->_left = cur->_left;
							}
						}
						delete cur;
						return true;
					}
					else 
					{
			        //左右子树均有节点,将删除节点替换为其右子树的最左节点(左子树的最右节点)
						Node* rightMinParent = cur;//考虑右子树的根节点为最左节点,不进循环
						Node* rightMin = cur->_right;
						while (rightMin->_left) 
						{
							rightMinParent = rightMin;
							rightMin = rightMin->_left;
						}
						cur->_key = rightMin->_key;
						if (rightMin == rightMinParent->_left) 
						{
							rightMinParent->_left = rightMin->_right;
                   //rightMin(右子树最左)为替换节点,替换后删除,rightMinParent的左或右指向rightMin的right
						}
						else 
						{
							rightMinParent->_right = rightMin->_right;
						}
						delete rightMin;
						return true;
					}
				}
			}
			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->_right == nullptr)
				{//删除节点右为空,将左节点赋值给要删除的节点
					root = root->_left;
				}
				else if (root->_left == nullptr)
				{//删除节点左为空,将右节点赋值给要删除的节点
					root = root->_right;
				}
				else
				{
					Node* rightMin = root->_right;
					while (rightMin->_left)
					{
						rightMin = rightMin->_left;
					}
					
					swap(root->_key, rightMin->_key);//交换删除节点和右子树节点的key值
					return _EraseR(root->_right, key);//交换后,删除节点为右子树最左节点,走left为空时情况
				}

				delete del;
				return true;
			}

		}

三、二叉搜索树的模拟实现

//二叉搜索树的模拟实现
namespace rab {
	template<class k>
	struct BSTreeNode {
		typedef BSTreeNode<k> Node;
		Node* _left;
		Node* _right;
		k _key;

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

	template<class k>
	class BSTree {
		typedef BSTreeNode<k> Node;
	public:
		//强制生成构造函数
		BSTree() = default;

		//拷贝构造函数
		BSTree(const BSTree<k>& t)
		{
			_root = Copy(t._root);//传入拷贝对象的根节点
		}

		//析构函数
		~BSTree() {
			Destroy(_root);
		}

		//插入
		bool Insert(const k& key) {
			if (_root == nullptr) {
				_root = new Node(key);
				return true;
			}
			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;//key值已存在
				}
			}
			cur = new Node(key);
			if (parent->_key < key) {
				parent->_right = cur;
			}
			if (parent->_key > key) {
				parent->_left = cur;
			}
			return true;
		}

		//查找
		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->_right)
							{//判断删除节点是parent的left还是right
								parent->_right = cur->_right;
							}
							else
							{
								parent->_left = cur->_right;
							}
						}
						delete cur;
						return true;
					}
					else if (cur->_right == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (cur == parent->_right)
							{//判断删除节点是parent的left还是right
								parent->_right = cur->_left;
							}
							else
							{
								parent->_left = cur->_left;
							}
						}
						delete cur;
						return true;
					}
					else 
					{
						//左右子树均有节点,将删除节点替换为其右子树的最左节点(左子树的最右节点)
						Node* rightMinParent = cur;//考虑右子树的根节点为最左节点,不进循环
						Node* rightMin = cur->_right;
						while (rightMin->_left) 
						{
							rightMinParent = rightMin;
							rightMin = rightMin->_left;
						}
						cur->_key = rightMin->_key;
						if (rightMin == rightMinParent->_left) 
						{
							rightMinParent->_left = rightMin->_right;//rightMin(右子树最左)为替换节点,替换后删除,rightMinParent的左或右指向rightMin的right
						}
						else 
						{
							rightMinParent->_right = rightMin->_right;
						}
						delete rightMin;
						return true;
					}
				}
			}
			return false;
		}
		
		/二叉搜索树的递归实现
		//递归查找
		bool FindR(const k& key)
		{
			return _FindR(key);
		}

		//递归插入
		bool InsertR(const k& key)
		{
			return _InsertR(_root, key);
		}

		//递归删除节点
		bool EraseR(const k& key)
		{
			return _EraseR(_root, key);
		}

		//中序遍历
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}


	private:
		//递归中序遍历
		void _InOrder(Node* root)
		{
			if (root == nullptr)
				return;

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

		//递归销毁搜索二叉树
		void Destroy(Node* root) {
			if (root == nullptr) {
				return;
			}
			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
		}

		//前序拷贝构造
		Node* Copy(Node* root) {
			if (root == nullptr) {
				return nullptr;
			}
			Node* newRoot = new Node(root->_key);
			newRoot->_left = Copy(root->_left);
			newRoot->_right = Copy(root->_right);
			return newRoot;
		}
		
		//递归查找
		bool _FindR(Node* root, const k& key)
		{
			if (root == nullptr)
				return false;

			if (root->_key < key)
			{
				return _FindR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _FindR(root->_left, key);
			}
			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->_right == nullptr)
				{
					root = root->_left;
				}
				else if (root->_left == nullptr)
				{
					root = root->_right;
				}
				else
				{
					Node* rightMin = root->_right;
					while (rightMin->_left)
					{
						rightMin = rightMin->_left;
					}
					
					swap(root->_key, rightMin->_key);
					return _EraseR(root->_right, key);//交换后,删除节点为右子树最左节点,走left为空时情况
				}

				delete del;
				return true;
			}

		}


	private:
		Node* _root = nullptr;
		};
	}

标签:right,cur,二叉,详解,key,数据结构,root,节点,left
From: https://blog.csdn.net/rab1211764820/article/details/137032700

相关文章

  • 函数是什么?C++函数详解!
    1、函数的声明和定义在复杂的程序中,如果全部的代码都写在main函数中,main函数体将非常庞大臃肿。把任务分工到其它的函数中,main函数只负责程序的核心流程,具体的任务由其它函数完成。这种思想就是模块化编程。声明和定义函数的语法:返回值的数据类型函数名(参数一的数据类型......
  • 核心子方法6: registerBeanPostProcessors(beanFactory)方法详解
    先总结: 该方法用于创建并注册Bean后处理器,先获取创建beanFactory中的BeanPostProcessor, 排序后注册到beanFactory中(beanFactory.addBeanPostProcessor(postProcessor)), 用于后面创建bean对象时使用注: 这里不会调用执行BeanPostProcessor, 在创建bean对象getBean->doG......
  • 详解SSL证书系列(6)了解HTTP及网络基础
    使用HTTP协议访问Web你知道当我们在网页浏览器(比如Chrome)的地址栏中输入URL时,Web网页是如何呈现的吗? Web页面当然不会凭空显示出来。根据Web浏览器地址栏中指定的URL,Web浏览器从Web服务器端获取文件资源等信息,从而显示出Web页面。像这种通过发送请求然后获取服务器资源的Web......
  • CocosCtreator知识点4:Creator中的坐标系和节点属性详解
    Creator中的坐标系和节点属性详解在CocosCreator中,游戏场景(Scene)是开发时组织内容的基础,也是呈现给玩家所有游戏内容的载体。而节点是场景的基础组成单位。可以把场景理解为组织内容的空间或平台,所有的内容(节点)通过其位置属性确定在该空间中的某个位置呈现。而为了确定空间......
  • 【机器学习】贝叶斯上篇(详解)
    深入理解贝叶斯学习:核心原理及应用全解析在机器学习的领域内,贝叶斯学习作为一种强大的框架,使我们能够在不确定性条件下进行预测和决策。贝叶斯学习源于托马斯·贝叶斯的工作,提供了一种概率论的学习方法,与传统的频率统计学提供了不同的视角。本文将深入探讨贝叶斯学习的核心原......
  • Python数据结构实验 递归算法设计
    一、实验目的1.掌握递归程序设计的基本原理和方法;2.熟悉数据结构中顺序表和单链表下的递归算法设计思想;3.掌握并灵活运用递归算法解决一些较复杂的应用问题。二、实验环境1.Windows操作系统的计算机2.Python3.7环境平台和PyCharm编辑器三、实验说明 1.实现递归算法的程序......
  • 面向对象08:封装详解
    packagecom.oop.demo04;//类private:私有publicclassStudent{//属性私有,封装大多数时候都是对于属性来的privateStringname;//名字,以前public所有人都可以操作这个名字,现在属性私有就不让所有人都可以操纵这个属性了privateintid;//学号priva......
  • 代码随想录第20天| 654.最大二叉树 617.合并二叉树
     654.最大二叉树654.最大二叉树-力扣(LeetCode)代码随想录(programmercarl.com)又是构造二叉树,又有很多坑!|LeetCode:654.最大二叉树_哔哩哔哩_bilibili给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建:创建一个根节点,其值为 ......
  • HashMap---数据结构
    目录一、基本数据结构二、树化与退化三、索引计算四、put方法和扩容五、并发问题六、key的设计一、基本数据结构        在jdk1.7版本的时候,hashmap结构主要是使用数组+链表的格式,而在jdk1.8版本中,hashmap的数据结构增加了一种“红黑树”的结构,即数组+(......
  • 根据后序(前序)和中序构造二叉树(力扣105,106)
    文章目录题目前知怎样通过中序和前(后)序构造二叉树HashMap题解一、思路二、解题方法三、Code总结题目Problem:105.从前序与中序遍历序列构造二叉树Problem:106.从中序与后序遍历序列构造二叉树中后:给定两个整数数组inorder和postorder,其中inorder......