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.其左右子树均为二叉搜索树

 

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

 3e383aaf2c9b4812b71bd7de8f90722a.png

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

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

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

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

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

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

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。

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

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.有左孩子或右孩子

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

 4bdbd809365a4c56a6973cd9a41c5fa9.png

代码如下: 

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. 大于所有左子树的值:即左子树的最大(最右)节点

用图像进行理解 

048b5551ed2342dab264d2efc7caa69c.png

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

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

最右节点可能有左子树。

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

代码如下

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

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

完整代码如下:

二叉搜索树的完整代码

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值