【数据结构】二叉搜索树

一、二叉搜索树的概念

⼆叉搜索树 ⼜称**⼆叉排序树**,它或者是⼀棵空树,或者是具有以下性质的⼆叉树:

①左子树不为空,则左子树节点值小于根节点值。
②右子树不为空,则右子树节点值大于根节点值。
③每个子树均为二叉搜索树。
中序遍历的结果是有序的

一般二叉搜索树不允许插入已有的值,但也有方法可以实现。

后面以二叉树为底层的容器:map,set,multimap,multiset,其中前两个不支持插入相等的值,而后两者便支持。

二、二叉搜索树的实现

节点实现

cpp 复制代码
template<class K>
struct BSTNode
{
	K _key;
	BSTNode<K>* _left;
	BSTNode<K>* _right;
	
	BSTNode(const K& key)
		:_key(key)
		,_left(nullptr)
		,_right(nullptr)
	{}

};

1.插入

为了保持其"左小右大"的特性,核心思路就是从根节点开始,寻找到一个合适的空位置进行插入。

如果树为空:直接将新节点作为根节点插入即可。

如果树不为空:从根节点开始,比较待插入节点和当前节点的值,小就插左边,大就插右边,循环找到一个合适的空位进行插入。

注意记录父亲节点的位置

代码实现:

cpp 复制代码
bool Insert(const K& key)
{
	if (_root == nullptr)
	{
		_root = new Node(key);
		return true;
	}

	Node* cur = _root;
	Node* parent = nullptr;

	while (cur)
	{
		if (key < cur->_key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (key > cur->_key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			return false;
		}

	}

	cur = new Node(key);
	if (parent->_key > key)
	{
		parent->_left = cur;
	}
	else
	{
		parent->_right = cur;
	}

	return true;
}

2.查找

1.从根开始比较,查找的值比根的值大则往右边走查找,反之则往左边走查找。

2.最多查找高度次,走到到空,还没找到,这个值不存在。

3.如果不支持插入相等的值,找到x即可返回

4.如果支持插入相等的值,一般要求查找中序的第一个x。

代码实现:

cpp 复制代码
	bool Find(const K& key)
	{

			Node* cur = _root;
			while (cur)
			{
				if (key < cur->_key)
				{
					cur = cur->_left;
				}
				else if (key > cur->_key)
				{
					cur = cur->_right;
				}
				else
				{
					return true;
				}

			}
			return false;

	}

3.删除(难点)

删除是其中实现难度较大的一点,我们要先查找,并且在删除后要保持二叉树的性质。

1)被删节点的左右孩子均为空

这种情况可直接删除,具体方法:让父亲结点指向空即可,若删除结点在左,那父亲左指向空,反之,父亲右指向空。

2)被删节点有一个孩子节点(左孩子/右孩子)

这种情况本质上就是让孩子节点顶替被删节点

3)被删节点存在两个孩子

这种情况采用替换法,就是用左子树的****最大结点/或者右子树的****最小结点去替换,交换后,在删除。

实现代码:

cpp 复制代码
bool Erase(const K& key)
{
	Node* cur = _root;
	Node* parent = nullptr;

	while (cur)
	{
		if (key < cur->_key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (key > cur->_key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else //找到了要删除的值了
		{
			if (cur->_left == nullptr)
			{
				if (cur == _root)
				{
					_root = cur->_right;
				}
				else
				{
					if (cur == parent->_left)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;
					}
				}
				delete cur;
			}
			else if (cur->_right == nullptr)
			{
				if (cur == _root)
				{
					_root = cur->_left;

				}
				else
				{
					if (cur == parent->_left)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;
					}

				}
				delete cur;

			}
			else
			{
				Node* replaceParent = cur;
				Node* replace = cur->_right;
				while (replace->_left)
				{
					replaceParent = replace;
					replace = replace->_left;
				}

				swap(cur->_key, replace->_key);


				if (replaceParent->_left == replace)
					replaceParent->_left = replace->_right;
				else
					replaceParent->_right = replace->_right;

				delete replace;

			}
		
			return true;
		}

	}
	return false;

}

4.中序遍历

InOrder() (公共接口): 这是给用户调用的函数。它内部直接调用私有的 _InOrder 函数,并从根节点 _root 开始遍历。

代码实现:

cpp 复制代码
	void InOrder()
	{
		_InOrder(_root);
		cout << endl;
	}

	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}

		_InOrder(root->_left);
		cout << root->_key << " ";
		_InOrder(root->_right);
	}

5.拷贝构造

代码实现:

cpp 复制代码
	BSTree(const BSTree<K>& t)
	{
		_root = Copy(t._root);
	}	

    Node* Copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* newroot = new Node(root->_key);
		newroot->_left = Copy(root->_left);
		newroot->_right = Copy(root->_right);
		return newroot;
	}

6.析构函数

cpp 复制代码
    ~BSTree()
	{
		Destoy(_root);
		_root = nullptr;
	}
    void Destoy(Node* root)
	{
		if (root == nullptr)
			return;
		Destoy(root->_left);
		Destoy(root->_right);
		delete root;
	}

三、二叉搜索树的性能

所以⼆叉搜索树增删查改时间复杂度为:O(N)

如果是一般情况下效率比较高,极端情况下效率就很低了。

以后学习的AVL树和红黑树可以解决这个问题。

相关推荐
小苏兮3 小时前
【数据结构】二叉搜索树
开发语言·数据结构·c++·学习·1024程序员节
晨曦(zxr_0102)3 小时前
CSP-X 2024 复赛编程题全解(B4104+B4105+B4106+B4107)
数据结构·c++·算法
ai安歌3 小时前
【Rust编程:从新手到大师】 Rust 控制流深度详解
开发语言·算法·rust
Shinom1ya_3 小时前
算法 day 36
算法
·白小白3 小时前
力扣(LeetCode) ——15.三数之和(C++)
c++·算法·leetcode
海琴烟Sunshine4 小时前
leetcode 268. 丢失的数字 python
python·算法·leetcode
CL.LIANG4 小时前
视觉SLAM前置知识:相机模型
数码相机·算法
无限进步_4 小时前
深入理解C语言scanf函数:从基础到高级用法完全指南
c语言·开发语言·c++·后端·算法·visual studio
Lei_3359674 小时前
[算法]十大排序
数据结构·算法·排序算法