从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修改为停车费用。

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

相关推荐
草履虫建模11 小时前
力扣算法 1768. 交替合并字符串
java·开发语言·算法·leetcode·职场和发展·idea·基础
naruto_lnq13 小时前
分布式系统安全通信
开发语言·c++·算法
学嵌入式的小杨同学13 小时前
【Linux 封神之路】信号编程全解析:从信号基础到 MP3 播放器实战(含核心 API 与避坑指南)
java·linux·c语言·开发语言·vscode·vim·ux
Re.不晚14 小时前
Java入门17——异常
java·开发语言
精彩极了吧14 小时前
C语言基本语法-自定义类型:结构体&联合体&枚举
c语言·开发语言·枚举·结构体·内存对齐·位段·联合
南极星100515 小时前
蓝桥杯JAVA--启蒙之路(十)class版本 模块
java·开发语言
baidu_2474386115 小时前
Android ViewModel定时任务
android·开发语言·javascript
CSDN_RTKLIB15 小时前
【四个场景测试】源文件编码UTF-8 BOM
c++
Dev7z15 小时前
基于 MATLAB 的铣削切削力建模与仿真
开发语言·matlab
不能隔夜的咖喱15 小时前
牛客网刷题(2)
java·开发语言·算法