数据结构-二叉树-二叉搜索树

一、概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者具有以下性质的二叉树:

若它的左子树不为空,则左树上所有节点的值都小于根节点的值。

若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。

它的左右子树也分别为二叉搜索树。最多找O(N)。

二、查找、插入、删除

插入

cpp 复制代码
bool Insert(K& k)
{
	
	if (_root == nullptr)
	{
		_root = new BSNode(k);
		return true;
	}
	BSNode* cur = _root;
	BSNode* parent = nullptr;
	while (cur)
	{
		if (cur->_k < k)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_k > k)
		{
			parent = cur;
			cur = cur->_left;
		}
	}
	if (parent->_k < k)
	{
		parent->_right = new BSNode(k);
	}
	else if (parent->_k > k)
	{
		parent->_left = new BSNode(k);
	}
	else
	{
		return false;
	}
	return true;
}

查找

cpp 复制代码
bool Find(K k)
{
	BSNode* cur = _root;
	while (cur)
	{
		if (cur->_k < k)
		{
			cur = cur->_right;
		}
		else if (cur->_k > k)
		{
			cur = cur->_left;
		}
		else
		{
			return true;
		}
	}
	return false;
}

删除

依次删除7、14、3、8。7和14属于直接删除的场景

3、8属于需要替换法进行删除的场景。

1、没有孩子

2、一个孩字

3、两个孩子,需要进行替换,也就是替换法,用左子树的最大节点或者右子树的最小节点。

最大节点为最右节点,最小节点就是最左节点 ,还需要处理要删除的节点为根节点,它没有左子树或者没有右子树的情况。

还有一种情况就是leftmax就是root的左子树的根,此时parent为nullptr所以我们需要让parent = cur

cpp 复制代码
void Erase(K& k)
{
	BSNode* cur = _root;
	BSNode* parent = nullptr;
	while (cur)
	{
		if (cur->_k < k)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_k > k)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			//开始托孤
			//要删除的节点,左孩子为空
			if (cur->_left == nullptr)
			{
				//需要判断删除节点就是根节点的情况
				if (cur == _root)
				{
					_root = cur->_right;
				}
				else
				{
					if (parent->_right == cur)
					{
						parent->_right = cur->_right;
					}
					else
					{
						parent->_left = cur->_right;
					}
				}
				
			}
			else if (cur->_right == nullptr)
			{
				if (cur == _root)
				{
					_root = cur->_left;
				}
				else
				{
					if (parent->_right == cur)
					{
						parent->_right = cur->_left;
					}
					else 
					{
						parent->_left = cur->_left;
					}
				}
			}
			else //两个孩子的情况,就需要替代法来删除
			{
				//找到左子树中最大的节点
				BSNode* leftMax = cur->_left;
				//注意为什么这里等于cur;
				BSNode* parent = cur;  
				while (leftMax->_right)
				{
					parent = leftMax;
					leftMax = leftMax->_right;
				}
				//找到以后把删除节点和leftmax节点的值做交换
				std::swap(cur->_k, leftMax->_k);

				//我们该把父亲的那个孩子和cur节点的孩子连接起来呢需要判断
				if (parent->_left == leftMax)
				{
					parent->_left = leftMax->_left;
				}
				else
				{
					parent->_right = leftMax->_left;
				}

				cur = leftMax;
			}

			delete cur;
			cur = nullptr;
		}
	}
}

有序数组:二分查找,问题:插入删除效率不行

二叉搜索树:插入删除效率还行。

如果退化成下面的情况,插入删除的效率就变成了O(N),所以我们引出了AVL树红黑树B树系列。

接下来我们看一下递归版本的删除,插入和发现

cpp 复制代码
bool _EraseR(BSNode*& root, const K& k)
{
	
	if (root == nullptr)
	{
		return false;
	}
	if (root->_k < k)
	{
		_EraseR(root->_right, k);
	}
	else if (root->_k > k)
	{
		_EraseR(root->_left, k);
	}
	else
	{
		BSNode* del = root;
		if (root->_left == nullptr)
		{
			root = root->_right;
		}
		else if (root->_right == nullptr)
		{
			root = root->_left;
		}
		else
		{
			BSNode* leftMax = root->_left;
			while (leftMax->_right)
			{
				leftMax = leftMax->_right;
			}
			std::swap(leftMax->_k, root->_k);

			return _EraseR(root->_left, k);
		}
		delete del;
		del = nullptr;
		return true;
	}
}
bool _InsertR(BSNode*& root,const K& k)
{
	if (root == nullptr)
	{
		root = new BSNode(k);
		return true;
	}
	if (root->_k < k)
	{
		_InsertR(root->_right, k);
	}
	else if (root->_k > k)
	{
		_InsertR(root->_left, k);
	}
	else
	{
		return false;
	}
}
bool _FindR(BSNode* root, const K& k)
{
	if (root == nullptr)
		return false;
	BSNode* cur = root;
	if (cur->_k < k)
	{
		_FindR(root->_right, k);
	}
	else if (cur->_k > k)
	{
		_FindR(root->_left, k);
	}
	else
	{
		return true;
	}
}
相关推荐
bkspiderx1 天前
C++经典的数据结构与算法之经典算法思想:贪心算法(Greedy)
数据结构·c++·算法·贪心算法
中华小当家呐1 天前
算法之常见八大排序
数据结构·算法·排序算法
tju新生代魔迷1 天前
数据结构:双向链表
数据结构·链表
songx_991 天前
leetcode9(跳跃游戏)
数据结构·算法·游戏
学c语言的枫子1 天前
数据结构——双向链表
c语言·数据结构·链表
Boop_wu1 天前
[数据结构] 栈 · Stack
数据结构
kk”1 天前
C语言快速排序
数据结构·算法·排序算法
3壹1 天前
数据结构精讲:栈与队列实战指南
c语言·开发语言·数据结构·c++·算法
papership1 天前
【入门级-算法-6、排序算法:选择排序】
数据结构·算法·排序算法
YS_Geo2 天前
Redis 深度解析:数据结构、持久化与集群
数据结构·数据库·redis