【C++】二叉搜索树

这篇具有很好参考价值的文章主要介绍了【C++】二叉搜索树。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

正文开始前给大家推荐个网站,前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

二叉搜索树

二叉搜索树的概念

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

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

【C++】二叉搜索树,C++,数据结构与算法,c++,数据结构,开发语言
这样一颗树就是标准的二叉搜索树。

二叉搜索树的实现

二叉搜索树最重要的就是插入和删除两个接口,我们重点说这两个接口。

结构:

  • 它的结构和二叉树差不多,一个左孩子指针一个右孩子指针,还有一个存储的值,但是这里我们需要套一层模板。
template <class T>
struct BSTreeNode
{
	BSTreeNode<T>* _left;
	BSTreeNode<T>* _right;
	T _key;
	
	//构造函数
	BSTreeNode(const T& key = 0)
		: _key(key)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

插入

插入还是比较简单的,如果插入的是第一个节点,既根节点是空的时候,我们直接new一个节点给_root就可以了,接下来就是需要找插入的位置,既然是二叉搜索树我们就要满足搜索二叉树的规则,如果要插入的值比_key大,我们就去搜索树的左边插入,如果要插入的值比_key小我们就去搜索树的左边插入,直到遇到nullptr节点,我们就可以开始插入了。

但是有一个问题,我们找到了nullptr,但是我们找不到它的父亲,所以我们还需要一个父节点指针来保存它的父亲。知道了它的父亲我们还是不知道要往父亲的左边插入还是父亲的右边插入,所以我们找到了也不能直接插入,还需要判断一下要插入的key和父亲的_key比较一下,大就往右边插入,小就往左边插入。
ps:二叉搜索树不能插入相同的值!!

bool Insert(const K& key)
{
	if (_root == nullptr)
	{
		_root = new Node(key);
		return true;
	}

	Node* parent = nullptr;
	Node* cur = _root;

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

	if (key > parent->_key)
	{
		parent->_right = new Node(key);
	}
	else
	{
		parent->_left = new Node(key);
	}
	return true;
}

删除

删除的话肯定要先在二叉树中找到该节点,找到后删除节点,但是不能直接删除节点,因为删除后依然要保持搜索二叉树的性质,所以找到需要删除的节点后,就有4种情况。

假设我们要删除3这个节点。

  1. 要删除的结点无孩子结点
    【C++】二叉搜索树,C++,数据结构与算法,c++,数据结构,开发语言

  2. 要删除的结点只有左孩子结点
    【C++】二叉搜索树,C++,数据结构与算法,c++,数据结构,开发语言

  3. 要删除的结点只有右孩子结点
    【C++】二叉搜索树,C++,数据结构与算法,c++,数据结构,开发语言

  4. 要删除的结点有左、右孩子结点
    【C++】二叉搜索树,C++,数据结构与算法,c++,数据结构,开发语言

前三种情况都好说,如果是只有左孩子节点,我们可以直接让它的父亲指向它的左孩子,如果是只有右孩子节点,我们可以让父亲直接指向它的右孩子,但是在这之前,我们需要看自己是父亲的左还是右,然后对应改变父亲指针就可以了,第一种情况可以分到第二种和第三种中,所以前三种是比较简单的。

最麻烦的就是它的左孩子和右孩子都存在,我们不能把孩子托管出去,这时我们需要使用替代法,我们需要找一个能够替代它的人,然后把它俩换一下,在进行删除。那么如何找这个能够替代它的节点呢?

我们想一下,这个节点需要满足搜索二叉树的性质,所以这个节点的值一定要比左孩子的孩子都大,并且要比右孩子的所有节点都小,基于这个原因,我们可以找左孩子的最大值节点or右孩子的最小节点来当这个替代节点,在搜索二叉树中,左边的最大节点一定是在最右边,右边的最小节点也一定在最左边,基于这个原因,我们就可以找到这个替代的节点。
ps:如果我们要找的这个节点就是这个左孩子的根或者右孩子的根节点,那么我们就不能直接连接,需要判断一下!

bool Erase(const K& key)
{
	Node* cur = _root;
	Node* parent = nullptr;
	//找需要删除的元素
	while (cur)
	{
		if (key > cur->_key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			if (key < cur->_key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//找到,开始删除

				//第一种情况,无左孩子
				if (cur->_left == nullptr)
				{
					if (parent == nullptr)
					{
						_root = cur->_right;
					}
					else
					{
						if (cur == parent->_left)
						{
							parent->_left = cur->_right;
						}
						else
						{
							parent->_right = cur->_right;
						}
					}
				}
				else
				{
					//第二种情况,无右孩子
					if (cur->_right == nullptr)
					{
						if (parent == nullptr)
						{
							_root = cur->_left;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
						}
					}
					else
					{
						//有两个孩子
						//找左孩子最大节点  -----右孩子最小节点同理
						Node* MaxRight = cur->_left;
						Node* parent = cur;
						while (MaxRight->_right)
						{
							parent = MaxRight;
							MaxRight = MaxRight->_right;
						}

						swap(cur->_key, MaxRight->_key);
						//到这里MaxRight一定无右孩子,如果parent->left==cur,说明一次也没找
						//那么就需要连接parent的_left,所以下面不能直接连接右孩子,需要进行判断
						if (parent->_left == MaxRight)
						{
							parent->_left = MaxRight->_left;
						}
						else
						{
							parent->_right = MaxRight->_left;
						}

						cur = MaxRight;
					}
				}
				delete cur;
				return true;
			}
		}
	}

	//找不到直接return
	return false;
}

查找

查找最简单,基于搜索二叉树的特性,我们可以和二分查找一样,大就去右边,小就去左边,到nullptr就是找不到。最多查找高度次!

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

由于搜索二叉树的特性,我们会发现二叉搜索树走一个中序遍历就是一个有序的数据,也由此二叉搜索树又称二叉排序树。

二叉搜索树的应用

K模型

K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
例如:给一个单词word,判断该单词是否拼写正确,我们可以这样做

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

KV模型

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

比如英汉词典就是英文与中文的对应关系。

总结:
二叉搜索树在最优情况心下的效率是O(logN),但是如果插入的是有序的数据搜索二叉树就会退化成单支树,此时效率会大大折扣,AVL树和红黑树不会出现这种情况!

那么今天的分享就到这里了,有什么不懂得可以私信博主,或者添加博主的微信,欢迎交流。文章来源地址https://www.toymoban.com/news/detail-803033.html

到了这里,关于【C++】二叉搜索树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 数据结构——二叉搜索树(附带C++实现版本)

    数据结构——二叉搜索树(附带C++实现版本)

    二叉搜索树又叫二叉排序树 ,二叉搜索树也是一种树形结构。 它是一课满足以下性质的搜索树: 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值 它的左右子树也分别是二叉搜索树 注意,二

    2024年02月12日
    浏览(8)
  • Java数据结构与算法:二叉搜索树

    Java数据结构与算法:二叉搜索树 大家好,我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿! 在计算机科学中,二叉搜索树(Binary Search Tree,简称BST)是一种常见的树形数据结构,它具有良好的查找和插入性能。每

    2024年01月24日
    浏览(14)
  • C++------利用C++实现二叉搜索树【数据结构】

    C++------利用C++实现二叉搜索树【数据结构】

    什么是二叉搜索树,二叉搜索树就是指左孩子永远比根小右孩子永远比根大。这个规则适用于所有的子树。 上面的就是一棵二叉搜索树,我们还可以发现这棵树走一个中序遍历序列是有序的,所以它又被称为二叉排序树。 二叉搜索树的操作主要分为以下几点,查找, 插入,

    2024年02月11日
    浏览(9)
  • 【算法与数据结构】700、LeetCode二叉搜索树中的搜索

    【算法与数据结构】700、LeetCode二叉搜索树中的搜索

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 :二叉搜索树(Binary Search Tree, BST)的性质:所有左子树节点键值 中间节点键值 所有右子树节点键值,并且左右子树都是二叉搜索树。那么我们根据此性质,对比目标值和中间节点,如

    2024年02月10日
    浏览(15)
  • 数据结构与算法-基础(十)平衡二叉搜索树

    摘要 二叉搜索树的特性-节点的左侧部分比它小,右侧部分比它大,使得二叉搜索树在查找节点有 二分法 的效果,也提高了它的添加和删除处理,毕竟添加和删除也是先查找位置,然后再处理。 平衡二叉搜索树 就是持续保证这样的高效性,进入正题: 二叉搜索树 在添加或

    2024年02月08日
    浏览(17)
  • [数据结构进阶 C++] 二叉搜索树(BinarySearchTree)的模拟实现

    [数据结构进阶 C++] 二叉搜索树(BinarySearchTree)的模拟实现

    二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值 它的左右子树也分别为二叉搜索树 我们先给出两个示例: 此

    2024年02月04日
    浏览(17)
  • 【算法与数据结构】98、LeetCode验证二叉搜索树

    【算法与数据结构】98、LeetCode验证二叉搜索树

    所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。    思路分析 :注意不要落入下面你的陷阱,笔者本来想左节点键值中间节点键值右节点键值即可,写出如下代码:   在leetcode执行时遇到下面的错误,再次读题,发现是所有左子树的键值小于

    2024年02月09日
    浏览(19)
  • 数据结构与算法之二叉树: Leetcode 98. 验证二叉搜索树 (Typescript版)

    验证二叉搜索树 https://leetcode.cn/problems/validate-binary-search-tree/ 描述 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树 有效 二叉搜索树定义如下: 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身

    2024年02月16日
    浏览(11)
  • 数据结构与算法(三):树论(树形结构、二叉树、二叉搜索树、红黑树、Btree&B+Tree、赫夫曼树、堆树)

    数据结构与算法(三):树论(树形结构、二叉树、二叉搜索树、红黑树、Btree&B+Tree、赫夫曼树、堆树)

    树论(树形结构、二叉树、二叉搜索树、红黑树、Btree、B+Tree、赫夫曼树、堆树) 在树形结构里面重要的术语: 结点:树里面的元素。 父子关系:结点之间相连的边 子树:当结点大于1时,其余的结点分为的互不相交的集合称为子树 度:一个结点拥有的子树数量称为结点的

    2024年02月01日
    浏览(13)
  • java数据结构与算法刷题-----LeetCode96. 不同的二叉搜索树

    java数据结构与算法刷题-----LeetCode96. 不同的二叉搜索树

    java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完): https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难,但它就是固定套路而已。其实动态规划只不过是将多余的步骤,提前放到dp数组中(就是一个数组,只

    2024年01月21日
    浏览(14)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包