C++:二叉搜索树的特点以及简易实现

二叉搜索树

二叉搜索树也叫二叉排序树,它可以是一棵空树。它具有一下特点:

  1. 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  2. 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  3. 它的左右子树也分别为二叉搜索树
  4. 没有键值(key)相等的节点

简单的说就是左边的值都比该节点的值小,右边的值都比该节点的值大
像这样:
在这里插入图片描述

二叉搜索树的查找

因为二叉搜索树的特点就是左边的值都比该节点的值小,右边的值都比该节点的值大,所以我们在进行查找的时候就通过key值比较,如果要查找的值比该节点的值小则去左子树查找,如果比该节点的值大则去右子树查找。
在这里插入图片描述
如上图,查找0,我们发现比5小,于是去5的左边找,比3小,于是去3的左边找,比1小,于是去1的左边找,然后找到了~
查找6,我们发现比5大,于是去5的右边找,比7小,于是去7的左边找,然后找到了~
代码实现

Node* Find(const K &k)
{
	Node* cur = _root;
	while (cur)
	{
		if (cur->_kv.first > k)
		{
			cur = cur->_left;
		}
		else if (cur->_kv.first < k)
		{
			cur = cur->_right;
		}
		else
			return cur;
	}
	return nullptr;
}

二叉搜索树的插入

因为二叉搜索树的性质,所以插入会有两种情况:
1.如果树为空,则直接插入
在这里插入图片描述
2.如果树不为空,那么需要找到对应的位置在进行插入,找位置的时候也要根据比该节点小去左边,比该节点大去右边的原则
在这里插入图片描述
如图,插入10,因为10比5大,所以去5的右子树,比7大,去7的右子树,比8大,去8的右子树,比9大,去9的右子树,9的右子树为空所以就插入这个新节点10

代码如下:

bool Insert(const std::pair<K, V> &kv)//插入
{
	//空树情况
	if (_root == nullptr)
	{
		_root = new Node(kv);
		return true;
	}
	//不为空树的情况
	Node* cur = _root;
	Node* parent = nullptr;
	//找到要插入的位置cur
	while (cur)
	{
		if (cur->_kv.first > kv.first)//插入的值比它小去左边
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (cur->_kv.first < kv.first)//插入的值比它大去右边
		{
			parent = cur;
			cur = cur->_right;
		}
		else//相等返回false
			return false;
	}
	//进行连接节点
	cur = new Node(kv);
	if (parent->_kv.first > cur->_kv.first)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}
	return true;
}

二叉搜索树的删除

删除一个节点有以下几种情况:

1.该节点的左子树为空,那么让该节点的父节点指向它的右子树

如下图,要删除的是8,那么它的左子树为空,就让它的父节点7指向它的右子树9。
在这里插入图片描述
另外还有一种特殊情况,如果左子树为空时,删除的正好是根节点,那么直接让根节点等于根节点的右子树。
如下图,删除的是5,5正好是根节点,因此直接让根节点指向它的右子树7。
在这里插入图片描述
代码如下:

if (cur->_left == nullptr)
{
	if (parent == nullptr)//删的是根节点
	{
		_root = cur->_right;//根等于根的右子树
	}
	else//删除的不是根节点,就让它的父节点指向它的右子树
	{
		if (parent->_left == cur)
		{
			parent->_left = cur->_right;
		}
		else
		{
			parent->_right = cur->_right;
		}
	}
}
2.该节点的右子树为空,那么让该节点的父节点指向它的左子树

如下图,要删除的是1,1的右子树为空,那么就让1的父节点3指向它的左子树0。
在这里插入图片描述
这里也有一种特殊情况,如果右子树为空时,删除的正好是根节点,那么直接让根节点等于根节点的左子树。
如下图,要删除的是5,正好是根节点,那么直接让根节点指向它的左子树3。
在这里插入图片描述
代码如下:

//接上情况1的代码

else if (cur->_right == nullptr)//要删除的是根节点
{
	if (parent == nullptr)
	{
		_root = cur->_left;
	}
	else//要删除的不是根节点,父节点指向它的左子树
	{
		if (parent->_left == cur)
		{
			parent->_left = cur->_left;
		}
		else
		{
			parent->_right = cur->_left;
		}
	}
}
3.该节点的左右子树都不为空,那么就要找一个节点来代替它

这个代替的节点也是有规律的,我们可以找右树的最左节点(左子树为空的节点),也可以找左树的最右节点(右子树为空的节点)。

方法1:找一个右树的最左节点来代替它
在这里插入图片描述

//方法1:找一个右树的最左节点来代替它
//右树的最左节点就是左为空的那个节点
Node* preplace = cur;
Node* replace = cur->_right;
while (replace->_left)
{
	preplace = replace;
	replace = replace->_left;
}
cur->_kv = replace->_kv;
del = replace;
//删除代替的最左节点(父亲指向它的右)
if (preplace->_left == replace)
{
	preplace->_left = replace->_right;
}
else
{
	preplace->_right = replace->_right;
}

方法2:找一个左树的最右节点来代替它
在这里插入图片描述

//方法2:找一个左树的最右节点来代替它
Node* preplace = cur;
Node* replace = cur->_left;
while (replace->_right)
{
	preplace = replace;
	replace = replace->_right;
}
cur->_kv = replace->_kv;
del = replace;
if (preplace->_left == replace)
{
	preplace->_left = replace->_left;
}
else
{
	preplace->_right = replace->_left;
}

二叉搜索树的遍历

采用中序遍历就能够按序打印这个二叉搜索树。
这里采用封装一层的方法,这样每次调用这个函数就不需要传参了。

void Inorder()//中序遍历
{
	_Inorder(_root);
	cout << endl;
}
void _Inorder(Node* root)
{
	if (root == nullptr)
		return;
	_Inorder(root->_left);
	cout << root->_kv.first << ":" << root->_kv.second << " ";
	_Inorder(root->_right);
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值