【数据结构】什么是二叉搜索(排序)树?

🦄个人主页:修修修也

🎏所属专栏:数据结构

⚙️操作环境:Visual Studio 2022


目录

📌二叉搜索(排序)的概念

📌二叉搜索(排序)的操作

🎏>二叉搜索的查找

🎏>二叉搜索的插入

🎏>二叉搜索的删除

📌二叉搜索(排序)的实现

📌二叉搜索(排序)的应用

🎏K模型

🎏KV模型

📌二叉搜索(排序)的性能分析

结语


📌二叉搜索(排序)的概念

        我们今天要介绍的是一种非常适合于搜索/排序的, 当然二叉搜索(排序)的前提是它是一颗,并且是一颗>二叉。因此对于以及>二叉的定义还有不太了解的朋友建议先移步这两篇博客补充一下数据结构的相关前置知识:

数据结构】什么是?icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_72357342/article/details/134973723?spm=1001.2014.3001.5502

数据结构】什么是>二叉?icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_72357342/article/details/135162895?sharetype=blogdetail&sharerId=135162895&sharerefer=PC&sharesource=weixin_72357342&spm=1011.2480.3001.8118

        >二叉搜索(BST, Binary Search Tree) 也称二叉排序或二叉查找。它或是一颗空,或是具有下列性质的>二叉:

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

        下图罗列了部分属于/不属于>二叉搜索>二叉以供参考:

        对于>二叉搜索而言,其中序遍历的结果恰好是中所有结点值的有序排列,因此特性也称其为二叉排序。构造一棵二叉排序的目的,其实并不是为了排序,而是为了提高查找和插入删除关键字的速度。不管怎么说,在一个有序数据集上的查找,速度总是要快于无序的数据集的,而二叉排序这种非线性的结构,同样有利于插入和删除操作的实现


📌二叉搜索(排序)的操作

        以如下>二叉搜索为例, 分别剖析>二叉搜索的查找,插入和删除操作:

int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };

🎏>二叉搜索的查找

        >二叉搜索的查找过程如下:

  1. 从根节点开始比较查找, 如果查找值比根结点值大,则往右子继续查找; 如果查找值比根结点值小,则往左子继续查找;
  2. 最多查找高度次, 即查找到叶子节点, 如果还没找到, 则该值不存在于此中。

🎏>二叉搜索的插入

        >二叉搜索的插入过程如下:

  1. 为空,则直接新增节点,赋值给根节点指针
  2. 不为空,则按>二叉搜索性质查找插入位置, 在查找到为空的位置插入新增值, 如果查找到该值已存在, 则返回查找失败(>二叉搜索不允许插入重复值)

🎏>二叉搜索的删除

        查找元素是否在二叉搜索中,如果不存在,则返回,如果存在,则待删除结点可能存在以下四种情况:

  1. 待删除结点无孩子结点
  2. 待删除结点只有左孩子结点(不管右孩子)
  3. 待删除结点只有右孩子结点(不管左孩子)
  4. 待删除结点左,右孩子结点都有

        在实际删除操作中,可以将1和2 / 3合并起来,因为我们的逻辑是哪边有孩子就管理,没有孩子就可以不管,因此无孩子结点既可以和不管右孩子结点情况合并又可以和不管左孩子情况合并,合并后实际的删除情况及过程如下三种:

  1. 删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除
  2. 删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除
  3. 在它的右子中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除


📌二叉搜索(排序)的实现

        由于本文偏向理论概念,篇幅有限,因此关于使用C++具体实现二叉搜索(排序)的详细过程我放在下面这篇文章中了,有需要的朋友可以移步这篇博客,里面有非常详细的使用C++实现二叉搜索(排序)的详解:【C++】模拟实现二叉搜索(排序)icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_72357342/article/details/142413312?spm=1001.2014.3001.5502        文章目录概览:


📌二叉搜索(排序)的应用

🎏K模型

        K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
        比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

  • 以词库中所有单词集合中的每个单词作为key,构建一棵>二叉搜索
  • >二叉搜索中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

🎏KV模型

        KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见:

  • 比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;
  • 再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对。

        >二叉搜索改key_value模型及其应用代码:

namespace key_value
{
	template<class K,class V>
	struct BSTreeNode
	{
		BSTreeNode<K,V>* _left;
		BSTreeNode<K,V>* _right;
		K _key;
		V _value;
		BSTreeNode(const K& key = K(), const V& value = V())
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
			, _value(value)
		{}
	};

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

		BSTree(const BSTree<K,V>& t)
		{
			_root = Copy(t._root);
		}

		BSTree<K,V>& operator=(BSTree<K,V> t)
		{
			swap(_root, t._root);
			return *this;
		}

		~BSTree()
		{
			Destroy(_root);
		}

		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

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

		bool InsertR(const K& key, const V& value)
		{
			return _InsertR(_root, key, value);
		}

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

	private:
		Node* Copy(Node* root)
		{
			if (root == nullptr)
				return nullptr;
			Node* copynode = new Node(root->_key);
			copynode->_left = Copy(root->_left);
			copynode->_right = Copy(root->_right);
			return copynode;
		}

		void Destroy(Node*& root)
		{
			if (root == nullptr)
				return;
			Destroy(root->_left);
			Destroy(root->_right);
			delete root;
			root == nullptr;
		}

		bool _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}
			if (root->_key < key)
			{
				_EraseR(root->_right, key);
			}
			else if (root->_key > key)
			{
				_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* leftMax = root->_left;
					while (leftMax->_right)
					{
						leftMax = leftMax->_right;
					}
					swap(root->_key, leftMax->_key);
					return _EraseR(root->_left, key);
				}
				delete del;
				return true;
			}
		}

		bool _InsertR(Node*& root, const K& key, const V& value)
		{
			if (root == nullptr)
			{
				root = new Node(key,value);
				return true;
			}
			if (root->_key < key)
			{
				_InsertR(root->_right, key, value);
			}
			else if (root->_key > key)
			{
				_InsertR(root->_left, key, value);
			}
			else
			{
				return false;
			}
		}

		Node* _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
			{
				return nullptr;
			}
			if (root->_key < key)
			{
				_FindR(root->_right, key);
			}
			else if (root->_key > key)
			{
				_FindR(root->_left, key);
			}
			else
			{
				return root;
			}
		}

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

		Node* _root;
	};

	void TestBSTree1()//小字典
	{
		BSTree<string, string> dict;
		dict.InsertR("insert", "插入");
		dict.InsertR("sort", "排序");
		dict.InsertR("right", "右边");
		dict.InsertR("date", "日期");

		string str;
		while (cin >> str)	//按Ctrl+Z终止输入
		{
			BSTreeNode<string, string>* ret = dict.FindR(str);
			if (ret)
			{
				cout << ret->_value << endl;
			}
			else
			{
				cout << "无该单词" << endl;
			}
		}
	}

	void TestBSTree2()//统计水果出现次数
	{
		string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };
		BSTree<string, int> countTree;
		for (const auto& str : arr)
		{
			// 先查找水果在不在搜索中
			// 1、不在,说明水果第一次出现,则插入<水果, 1>
			// 2、在,则查找到的节点中水果对应的次数++
			BSTreeNode<string, int>* ret = countTree.FindR(str);
			if (ret == NULL)
			{
				countTree.InsertR(str, 1);
			}
			else
			{
				ret->_value++;
			}
		}
		countTree.InOrder();
	}
}


📌二叉搜索(排序)的性能分析

        插入和删除操作都必须先查找,查找效率代表了>二叉搜索中各个操作的性能。

        对有n个结点的>二叉搜索,若每个元素查找的概率相等,则>二叉搜索平均查找长度是结点在>二叉搜索的深度的函数,即结点越深,则比较次数越多。
        但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的>二叉搜索:

  • 最优情况下,>二叉搜索为完全>二叉(或者接近完全>二叉),其平均比较次数为:$log_2 N$
  • 最差情况下,>二叉搜索退化为单支(或者类似单支),其平均比较次数为:$\frac{N}{2}$

结语

希望这篇关于 二叉搜索(排序) 的博客能对大家有所帮助,欢迎大佬们留言或私信与我交流.

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐

数据结构】什么是线性表?

数据结构】线性表的链式存储结构

数据结构】什么是栈?

数据结构】什么是?

数据结构】什么是队列?

数据结构】什么是堆?

数据结构】什么是?

数据结构】什么是>二叉?



http://www.niftyadmin.cn/n/5679428.html

相关文章

Linux相关概念和重要知识点(8)(操作系统、进程的概念)

1.操作系统&#xff08;OS&#xff09; &#xff08;1&#xff09;基本结构的认识 任何计算机系统都包含一个基本的程序集合&#xff0c;用于实现计算机最基本最底层的操作&#xff0c;这个软件称为操作系统。操作系统大部分使用C语言编写&#xff0c;少量使用汇编语言。 从…

宝塔面板部署雷池社区版教程

宝塔面板部署雷池社区版教程 简单介绍一下宝塔面板&#xff0c;安全高效的服务器运维面板&#xff0c;使用宝塔面板的人非常多 在网站管理上&#xff0c;许多用户都是通过宝塔面板进行管理&#xff0c;宝塔面板的Nginx默认监听端口为80和443&#xff0c;这就导致共存部署时雷池…

【linux】轻松掌握文件管理:安装Ranger并设置Micro为默认编辑器

在Linux系统中&#xff0c;高效的文件管理和文本编辑是日常工作的重要组成部分。今天&#xff0c;我们将介绍如何安装强大的命令行文件管理器Ranger&#xff0c;并将现代化的终端文本编辑器Micro设置为默认编辑器。这个组合不仅能提高您的工作效率&#xff0c;还能让您的终端操…

vue echarts tooltip使用动态模板

先上代码 tooltip: {// 这里是车辆iconshow: true,// trigger: "item",// backgroundColor: "transparent",appendToBody: true,textStyle: {color: "#ffffff" //设置文字颜色},formatter: (params) > {return formatHtml(params.data)},}, …

三十二、领域驱动设计DDD(战术设计)

DDD 战术设计详解与实例 DDD 的战术设计关注如何在具体实现中应用领域模型的原则&#xff0c;包括聚合、服务、工厂等设计模式。以下是每个核心概念的详细介绍和实例。 1 聚合 (Aggregate) 定义&#xff1a;聚合是一组相关联的对象&#xff0c;它们共同表现一个一致的业务规…

使用rust实现rtsp码流截图

中文互联网上的rust示例程序源码还是太稀少&#xff0c;找资料很是麻烦&#xff0c;下面是自己用业余时间开发实现的一个对批量rtsp码流源进行关键帧截图并存盘的rust demo源码记录。 要编译这个源码需要先安装vcpkg&#xff0c;然后用vcpkg install ffmpeg安装最新版本的ffmpe…

网络编程(11)——另一种简便的粘包处理方式

十一、day11 下午学习如何使用asio库用另一种比较简便的方式处理粘包问题&#xff0c;之前有提过一种粘包处理方式&#xff1a;通过async_read_some函数监听读事件&#xff0c;并在读事件的回调函数HandleRead中对数据进行处理 _socket.async_read_some(boost::asio::buffer(…

python 图像绘制问题: 使用turtle库绘制蟒蛇

turtle &#xff08;海龟)库是turtle绘图体系的python实现。 1969年诞生&#xff0c;主要用于程序设计入门。 import turtle turtle.setup(650, 350, 200, 200) # 设置窗体&#xff08;宽&#xff0c;高&#xff0c;窗体左上角x坐标&#xff0c;y坐标&#xff09; turtl…