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.总结

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

完整代码如下:

二叉搜索树的完整代码

相关推荐
一点媛艺2 小时前
Kotlin函数由易到难
开发语言·python·kotlin
姑苏风2 小时前
《Kotlin实战》-附录
android·开发语言·kotlin
奋斗的小花生3 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程3 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
UestcXiye4 小时前
《TCP/IP网络编程》学习笔记 | Chapter 3:地址族与数据序列
c++·计算机网络·ip·tcp
Chrikk4 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*4 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue4 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang