从C++开始的编程生活(18)——二叉搜索树基础

前言

本系列文章承接C++基础的学习,需要++有C语言的基础++ 才能学会哦~

第18篇主要讲的是有关于C++的**++二叉搜索树基础++** 。
C++才起步,都很简单!!

目录

前言

二叉搜索树

性能分析

二叉搜索树的增删查改

插入

查询

删除

修改

二叉搜索树的key和key/value的搜索场景

key搜索场景

key/value搜索场景


二叉搜索树

具有以下性质的二叉树:

若左子树不为空,则左子树上所有结点****≤**根结点的值
若右子树不为空,则
右子树上所有结点****≥**根结点的值
它的左右子树也分别为二叉搜索树

称之为二叉搜索树。++特别的,空树也是二叉搜索树++

也可以反过来,右 ≤ 根 ≤ 左。

图1

二叉搜索树,又叫二叉排序树

当我们将二叉搜素树++中序(左根右)输出后,为升序数列++ 。

上图中序输出为:1,3,6,7,8,10,15,17,19,27,30。

那么顾名思义,这种结构的作用就是++Ⅰ.便于搜索++ ,++Ⅱ.便于排序++。

根据二叉搜索树的性质,我们在查找结点的时候++最多只需要查找n次,n为树的层数++,搜索速度很快。

性能分析

如图,结点大小和上图完全相同,但是排列情况不同,层数更大,但也是二叉搜索树。

图2

这时的搜索,最多就要搜索11层,比原来多了7层!++这说明二叉搜索树排列不同,搜索性能是不同的,波动很大++,因此,我们实际上使用更多的是平衡二叉搜索树(如图1),这个后面再学,先按下不表。

二叉搜索树的增删查改

cpp 复制代码
template<class K>
struct BSTNode
{
	K _key;
	BSTNode<K>* _right;
	BSTNode<K>* _left;
	BSTNode(const K& key)
		:_key(key)
		,_left(nullptr)
		,_right(nullptr)
	{}
};

二叉搜索树结点结构代码

插入

如果++树为空++ ,则直接新增结点,赋值给root指针。
如果++树不为空++ ,++按照二叉搜索树性质++,++大往右,小往左,找空插++ 。插入值比当前结点大就往右走,插入值比当前结点小就往左走,找到空位插入新结点。
++插入相等的值时,可以往右也可以往左,但是要注意保持一致性++,要么都往右要么都往左。有相同的值,称为冗余,我们一般默认不存相同的数值。

但是如果进行了旋转子树的操作,那么即使插入时统一了,实际存储也不一定就是预料的那样。

cpp 复制代码
boll Insert(const K& key)//默认不支持冗余
{
	if (_root == nullptr)
	{
		_roor = new Node(key);
		return true;
	}
	
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
		if (cur->_key < key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (cur->_key > key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			return false;
		}
	}
	cur = new Node(key);
	if (parent->_key < key)
	{
		parent->_right = cur;
	}
	else
	{
		parent->_left = cur;
	}
	return true;
}

查询

无冗余查找:

cpp 复制代码
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;
}

存在冗余查找:

比如要求找到重复对象中的中序输出的第一个。

在上述代码的基础上,查找到相等数值的节点后不返回,继续在左子树中找目标对象,找到了再输出true

代码略······

删除

首先查找结点,在树中再进行删除。

情况①: 删除的是叶子结点。

解决方法:++直接释放删除++。

情况②: 删除的结点只有一个孩子。

解决方法:让++父结点的孩子指针指向孩子的孩子++,然后再删除释放中间结点

情况③: 删除的结点有两个孩子。

解决方法:用++右子树的最小结点++ or++左子树的最大结点替代该结点++,替代完成后,再删除释放中间结点。

因为++空树也能算是二叉搜索树++,所以我们可以把++叶子结点当作是有两个孩子且都为空树的结点++,++并且并到情况②中进行处理++。

cpp 复制代码
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->_right = cur->_right;
					}
					else
					{
						parent->left = cur->left;
					}
				}
				delete cur;
				return true;
			}
			else if (cur->_right == nullptr)
			{
            //删除根结点的特殊情况处理
				if (cur == _root)
				{
					_root = cur->_left;
				}
				else
				{
					if (cur == parent->_right)
					{
						parent->_right = cur->_left;
					}
					else
					{
						parent->_left = cur->_left;
					}
				}
				delete cur;
				return true;
			}
        //情况三
			else
			{
				//找右子树最小结点替代
				Node* minRight = cur->_right;
				Node* minRightParent = cur;
				while (minRight->_left)
				{
					minRightParent = minRight;
					minRight = minRight->_left;
				}

				cur->_key = minRight->_key;
                //进入了while循环
				if (minRightParent->left == minRight)
				{
					minRightParent->_left = minRight->_right;
				}
                //未进入while循环
				else
				{
					minRightParent->_right = minRight->_right;
				}
				return true;
				delete minRight;

			}
		}
	}
	return false;
}

修改

**二叉搜索树的关键码(作为排列根据的数值key)不可修改。**否则可能会破坏二叉搜索树的规则。

修改操作只能修改关键值和父母孩子指针之外的成员变量,所以实际修改时,就是先查找再自定义修改可修改的值,没什么特别的。

二叉搜索树的key和key/value的搜索场景

key搜索场景

只有key作为关键码时进行的搜索。

此时,结构中只存储key就好了,key为用来排列二叉搜索树的依据。这种场景下的搜索场景支持增删查,但是不可以改,理由可见上文"修改"部分。

**生活中使用场景:**业主开车进小区停车场,扫描车牌,以车牌为关键码搜索该车牌是否为本小区车辆。

key/value搜索场景

每一个key关键码都有与之对应的值value,value可为任意对象。

此时,除了key,还要存储value。增删查依旧用key按照二叉搜索树的规则进行搜索,然后可以根据key找到对应的value。key不可修改,但是value可以。

**生活中使用场景:**简单中英文互译字典,可英文作key,中文作value;商城车库,以车牌号为key,车辆入场后value记录为入场时间,出场之后,以车牌号key查找到对应的入场时间,然后再用出场时间减去value的入场时间,得出停车时间,接着计算出停车费用,value修改为停车费用。

❤~~本文完结!!感谢观看!!接下来更精彩!!欢迎来我博客做客~~❤

相关推荐
FAFU_kyp1 小时前
Rust 泛型(Generics)学习教程
开发语言·学习·rust
VekiSon1 小时前
ARM架构——C 语言+SDK+BSP 实现 LED 点灯与蜂鸣器驱动
c语言·开发语言·arm开发·嵌入式硬件
研☆香1 小时前
JavaScript 历史列表查询的方法
开发语言·javascript·ecmascript
Java程序员威哥1 小时前
【包教包会】SpringBoot依赖Jar指定位置打包:配置+原理+避坑全解析
java·开发语言·spring boot·后端·python·微服务·jar
a程序小傲2 小时前
中国邮政Java面试被问:边缘计算的数据同步和计算卸载
java·服务器·开发语言·算法·面试·职场和发展·边缘计算
Java程序员威哥2 小时前
Java微服务可观测性实战:Prometheus+Grafana+SkyWalking全链路监控落地
java·开发语言·python·docker·微服务·grafana·prometheus
全栈软件开发2 小时前
PHP实时消息聊天室源码 PHP+WebSocket
开发语言·websocket·php
王老师青少年编程2 小时前
2024年6月GESP真题及题解(C++七级): 黑白翻转
c++·题解·真题·gesp·csp·七级·黑白翻转
ouliten2 小时前
C++笔记:std::span
c++·笔记