C++高阶:二叉搜索树

博主CSDN主页:all4x的主页

专栏分类:CPP从入门到精通

博主的代码仓库:all4x的仓库

二叉搜索树

1.写在开始前

2.二叉树的概念及其性质

3.二叉搜索树的模拟实现

5.二叉搜索树的插入

6.二叉搜索树的删除分析

7.总结


1.写在开始前

学到这里,我们就要将c++的学习难度提升一个档次,后续c++高阶的学习主要包括

1.二叉搜索树 2.AVL树 3.红黑树 4.哈希表 5.C++11 6.智能指针等

这部分学习固然困难,但是也是拉开差距的关键时期,我们一起加油!

本章将为大家介绍二叉搜索树,这一章节的学习是为后续对AVL树和红黑树的学习打下基础!

2.二叉树的概念及其性质

二叉树搜索树(BianrySearchTree):又称二叉排序树、二叉查找树。

其性质如下

1.节点值大的在右侧,节点值小的在左侧


2.其左右子树均为二叉搜索树

如下图,就是一个二叉搜索树。大家结合图像来理解。

根据二叉搜索树的性质我们不难发现其中序遍历为有序序列,上图中序遍历结果应为

【1,3,4,6,7,8,10,14,13】

同时,对于一颗二叉搜索树我们仅支持增删查而不支持改,因为一旦修改可能会影响整棵二叉搜索树的平衡。

3.二叉搜索树的模拟实现

还是老样子,对一个数据结构的模拟实现,首先写出基本框架。

对一个树形结构而言,其节点包含左右指针和自身的值,因此实现代码如下。

cpp 复制代码
template<class K>//模板参数,方便对节点的数据类型进行控制
struct BSTreeNode//定义结点的结构
{
	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	K _key;
	BSTreeNode(const K& key)//初始化列表
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
	{}
};

5.二叉搜索树的插入

对于二叉搜索树的插入的原理非常简单,根据二叉搜索树左小右大的性质不难知道,插入值小往左走,插入值大往右走。若树中已经有相等的值,则不插入返回false。

首先找到插入值应该在位置,而后与其前后节点进行链接,实现插入操作。

cpp 复制代码
bool insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);//对结点Node的空间开辟
			return true;
		}
		Node* cur = _root;//记录当前结点
		Node* prev = nullptr;//记录当前结点的前一个结点,以便后续插入的时候进行大小比较
		while (cur)//结点的插入
		{
			if (cur->_key < key)//小值往左走
			{
				prev = cur;
				cur = cur->_right;
			}
			else if (cur->_key > key)//大值往右走
			{
				prev = cur;
				cur = cur->_left;
			}
			else//相同的值不需要插入
				return false;
		}
		cur = new Node(key);//先找到位置,再对key进行节点的空间开辟
		if (prev->_key > key)//cur与prev间产生连接
		{
			prev->_left = cur;
		}
		else
		{
			prev->_right = cur;
		}
		return true;
	}

6.二叉搜索树的删除分析

删除操作相对于插入的操作稍许复杂。分为四种情况

1.删除的节点没有左右孩子

2.删除的节点只有左孩子

3.删除的节点只有右孩子

4.删除的节点左右节点均存在

下面我们来进行分析。

1.没有左右孩子

直接进行删除即可。

2.有左孩子或右孩子

若是有左节点或有右节点,我们仅需将其的左孩子和右孩子与其父亲链接即可。

代码如下:

cpp 复制代码
bool Erase(const K& key)//节点的删除
	{
		Node* prev = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key > key)//要删除的节点比当前节点小,往左边走
			{
				prev = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)//要删除的节点比当前节点大,往右边走
			{
				prev = cur;
				cur = cur->_right;
			}
			else//找到要删除的节点,准备进行删除 
			{
				if (cur->_left == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_right;
					}
					else 
					{
						if (cur == prev->_left)
						{
							prev->_left == cur->_right;
						}
						else
						{
							prev->_right = cur->_right;
						}
					}
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->_left;
					}
					else {
						if (cur == prev->_left)
						{
							prev->_left == cur->_left;
						}
						else if (cur == prev->_right)
						{
							prev->_right == cur->_left;
						}
					}
					delete cur;
				}

4.左孩子与右孩子均存在

若左右孩子均存在,我们这里用到的处理方法叫做替换法。

由于二叉搜索树的性质,为使删除后树的平衡不被破坏,我们删除的节点应被替换合适的值。

那么,什么值是合适的呢。

  1. 小于所有右子树的值:即右子树的最小(最左)节点
  2. 大于所有左子树的值:即左子树的最大(最右)节点

用图像进行理解

同时我们需要考虑的一个问题是,被替换的节点可能有后续节点。

比如最左节点可能有右子树。

最右节点可能有左子树。

因此在替换后,还需对替换的节点后续节点进行链接操作。

代码如下

cpp 复制代码
else//左右都不为空 
				{
					Node* prev = cur;
					Node* subLeft = cur->_right;
					while (subLeft->_left)
					{
						prev = subLeft;
						subLeft = subLeft->_left;
					}
					swap(cur->_key, subLeft->_key);//交换两个节点的值而不改变连接情况
					if (subLeft == prev->_left)
						prev->_left = subLeft->_right;//subleft无左节点但可能有右节点
					else//subleft为该右子树的第一个节点 
					{
						prev->_right = subLeft->_right;
					}
					delete subLeft;
				}

7.总结

二叉搜索的最常用的操作我们在本篇文章已经介绍完毕,但是既然是树形结构,那么便可以用递归的方式进行模拟实验,大家可以自行尝试。

完整代码如下:

二叉搜索树的完整代码

相关推荐
没有梦想的咸鱼185-1037-16634 分钟前
基于R语言机器学习方法在生态经济学领域中的实践技术应用
开发语言·机器学习·数据分析·r语言
向上的车轮29 分钟前
基于go语言的云原生TodoList Demo 项目,验证云原生核心特性
开发语言·云原生·golang
The Chosen One98530 分钟前
C++ : AVL树-详解
开发语言·c++
zzyzxb34 分钟前
std::enable_shared_from_this
c++
SNAKEpc1213840 分钟前
QML和Qt Quick
c++·qt
PH_modest40 分钟前
【Qt跬步积累】—— 初识Qt
开发语言·qt
hansang_IR1 小时前
【题解】洛谷 P4286 [SHOI2008] 安全的航线 [递归分治]
c++·数学·算法·dfs·题解·向量·点积
GanGuaGua1 小时前
Linux系统:线程的互斥和安全
linux·运维·服务器·c语言·c++·安全
怀旧,1 小时前
【C++】18. 红⿊树实现
开发语言·c++
lsnm1 小时前
【LINUX网络】IP——网络层
linux·服务器·网络·c++·网络协议·tcp/ip