二叉搜索树

一、二叉搜索树的概念

二叉搜索树又称二叉排序树,它可能是一棵空树,也可能是一颗具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值。
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值。
它的左右子树也分别为二叉搜索树。

二、Key模型的二叉搜索树的实现

2.1 二叉搜索树的树节点的设计

	template <class K>
	struct BSTreeNode
	{
		BSTreeNode<K>* _left;
		BSTreeNode<K>* _right;
		K _val;

		BSTreeNode(const K& val)
			:_left(nullptr)
			, _right(nullptr)
			, _val(val)
		{}
	};

2.2 查找接口

从跟节点开始查找目标节点,如果目标值比根节点的值小就到根的左子树中查找,如果目标值比根节点的值大就到根节点的右子树中查找,如果找到了就返回,如果找到叶子节点都没有找到目标节点,那么该目标节点并不存在这颗二叉搜索树中。

代码实现(非递归):

bool Find(const K& key)
{
	Node* cur = _root;
	while (cur)
	{
		if (key < cur->_val)
		{
			cur = cur->_left;
		}
		else if (key > cur->_val)
		{
			cur = cur->_right;
		}
		else
		{
			return true;
		}
	}

	return false;
}

(递归):

bool FindR(const K& key)
{
	return _FindR(_root, key);
}

bool _FindR(Node* root, const K& key)
{
	if (root == nullptr)
	{
		return false;
	}
	if (root->_val < key)
	{
		return _FindR(root->_right, key);
	}
	else if (root->_val > key)
	{
		return _FindR(root->_left, key);
	}
	else
	{
		return true;
	}
}

2.3 插入接口

要想插入某个节点需要先找到该节点要插入的位置,所以跟查找的逻辑非常的像。
如果root本身是空树,就new一个key的节点给root即可。
key_val,就往左树走,key>root->_val,就往右树走,如果遇到相等的节点就应该返回了,不能插入(二叉搜索树的性质),一直走直到走到一个空树,那么这个位置就是新结点插入的位置,但是在插入之前要先用key值与该空节点的父节点的值比较一下,如果key>parent->_val,就插入到parent->right;
如果key_val。就插入到parent->left。

演示如下:
在这里插入图片描述
在这里插入图片描述
代码实现(非递归):

		bool Insert(const K& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (key > cur->_val)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (key < cur->_val)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}
			Node* newNode = new Node(key);
			if (key < parent->_val)
			{
				parent->_left = newNode;
			}
			else
			{
				parent->_right = newNode;
			}
			return true;
		}

(递归):

bool InsertR(const K& key)
{
	return _InsertR(_root, key);
}
//注意这里用的是Node*&,代表的是上一层递归的左子树指针或者右子
//树指针的别名,直接赋值就相当于赋值给上一层递归的左子树指针
//或者右子树指针,自然就连接上了,所以无需从父节点的left或
//者right进行修改
bool _InsertR(Node*& root, const K& key)
{
	if (root == nullptr)
	{
		root = new Node(key);
		return true;
	}
	if (root->_val < key)
	{
		return _InsertR(root->_right, key);
	}
	else if (root->_val > key)
	{
		return _InsertR(root->_left, key);
	}
	else
	{
		return false;
	}
}

2.4 删除接口

在这里插入图片描述
代码实现(非递归):

bool Erase(const K& key)
{
	Node* parent = nullptr;
	Node* cur = _root;
	while (cur)
	{
		if (key > cur->_val)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (key < cur->_val)
		{
			parent = cur;
			cur = cur->_left;
		}
		else
		{
			//1、左树为空
			if (cur->_left == nullptr)
			{
				//删除根节点
				if (cur == _root)
				{
					_root = cur->_right;
				}
				else
				{
					if (parent->_left == cur)
					{
						parent->_left = cur->_right;
					}
					else if (parent->_right == cur)
					{
						parent->_right = cur->_right;
					}
				}

			}
			//2、右树为空
			else if (cur->_right == nullptr)
			{
				//删除根节点
				if (cur == _root)
				{
					_root = cur->_left;
				}
				else
				{
					if (parent->_left == cur)
					{
						parent->_left = cur->_left;
					}
					else if (parent->_right == cur)
					{
						parent->_right = cur->_left;
					}
				}

			}
			//左右树都不为空
			else
			{
				//如图有特殊情况,parent不能初始化为nullptr
				Node* parent = cur;
				//找左树的最大节点
				Node* leftMax = cur->_left;
				while (leftMax->_right)
				{
					parent = leftMax;
					leftMax = leftMax->_right;
				}
				swap(leftMax->_val, cur->_val);

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

				//交换后需要更新cur
				cur = leftMax;
			}

			delete cur;
			cur = nullptr;
			return true;
		}
	}

	return false;
}

递归:

bool EraseR(const K& key)
{
	return _EraseR(_root, key);
}

```cpp
//这里也是Node*&,原因同上面插入的非递归
bool _EraseR(Node*& root, const K& key)
{
	if (root == nullptr)
	{
		return false;
	}
	if (root->_val < key)
	{
		return _EraseR(root->_right, key);
	}
	else if (root->_val > key)
	{
		return _EraseR(root->_left, key);
	}
	else
	{
		//1、左子树为空
		//2、右子树为空
		//3、左右子树都不为空
		if (root->_left == nullptr)
		{
			Node* del = root;
			//root是上一层的引用,修改root等于修改上一层的指
			//针,等于修改parent的指针,符合题意
			root = root->_right;
			delete del;
			del = nullptr;
		}
		else if (root->_right == nullptr)
		{
			Node* del = root;
			root = root->_left;
			delete del;
			del = nullptr;
		}
		else
		{
			Node* leftMax = root->_left;
			while (leftMax->_right)
			{
				leftMax = leftMax->_right;
			}
			swap(leftMax->_val, root->_val);
			_EraseR(root->_left, key);
		}

		return true;
	}
}

2.5 拷贝构造

拷贝构造就是把被拷贝的树利用前序遍历来新建一颗树即可。
先创建根节点,再递归创建左子树,最后递归创建右子树。

	//拷贝构造
BSTree(const BSTree<K>& t)
{
	_root = Copy(t._root);
}

Node* Copy(Node* root)
{
	if (root == nullptr)
	{
		return nullptr;
	}
	//构建根
	Node* newTree = new Node(root->_val);
	//构建左子树
	newTree->_left = Copy(root->_left);
	//构建右子树
	newTree->_right = Copy(root->_right);

	//返回这棵树
	return newTree;
}

2.6 赋值重载

	//赋值
	//依然是利用现代写法,利用传参的拷贝构造得到一颗
	//局部临时的树,再交换root指针即可
	BSTree<K>& operator=(BSTree<K> t)
	{
		swap(_root, t._root);
		return *this;
	}

2.7 析构函数

析构函数就是利用后序遍历的思想把整棵树的每一个节点释放掉,即先析构左子树,再析构右子树,最后析构根节点。

//析构
~BSTree()
{
	_Destroy(_root);
}
void _Destroy(Node* root)
{
	if (root == nullptr)
	{
		return;
	}
	if (root->_left)
	{
		_Destroy(root->_left);
	}
	if (root->_right)
	{
		_Destroy(root->_right);
	}
	delete root;
	root = nullptr;
}

三、key模型二叉搜索树参考代码

namespace key
{
	template <class K>
	struct BSTreeNode
	{
		BSTreeNode<K>* _left;
		BSTreeNode<K>* _right;
		K _val;

		BSTreeNode(const K& val)
			:_left(nullptr)
			, _right(nullptr)
			, _val(val)
		{}
	};

	template <class K>
	class BSTree
	{
		typedef BSTreeNode<K> Node;
	public:
		BSTree()
			:_root(nullptr)
		{}

		bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (key < cur->_val)
				{
					cur = cur->_left;
				}
				else if (key > cur->_val)
				{
					cur = cur->_right;
				}
				else
				{
					return true;
				}
			}

			return false;
		}



		bool Insert(const K& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (key > cur->_val)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (key < cur->_val)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}
			Node* newNode = new Node(key);
			if (key < parent->_val)
			{
				parent->_left = newNode;
			}
			else
			{
				parent->_right = newNode;
			}
			return true;
		}

		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (key > cur->_val)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (key < cur->_val)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//1、左树为空
					if (cur->_left == nullptr)
					{
						//删除根节点
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_right;
							}
							else if (parent->_right == cur)
							{
								parent->_right = cur->_right;
							}
						}

					}
					//2、右树为空
					else if (cur->_right == nullptr)
					{
						//删除根节点
						if (cur == _root)
						{
							_root = cur->_left;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_left;
							}
							else if (parent->_right == cur)
							{
								parent->_right = cur->_left;
							}
						}

					}
					//左右树都不为空
					else
					{
						//如图有特殊情况,parent不能初始化为nullptr
						Node* parent = cur;
						//找左树的最大节点
						Node* leftMax = cur->_left;
						while (leftMax->_right)
						{
							parent = leftMax;
							leftMax = leftMax->_right;
						}
						swap(leftMax->_val, cur->_val);

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

						//交换后需要更新cur
						cur = leftMax;
					}

					delete cur;
					cur = nullptr;
					return true;
				}
			}

			return false;

		}

		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

		bool FindR(const K& key)
		{
			return _FindR(_root, key);
		}

		bool InsertR(const K& key)
		{
			return _InsertR(_root, key);
		}

		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}

		//析构
		~BSTree()
		{
			_Destroy(_root);
		}

		//拷贝构造
		BSTree(const BSTree<K>& t)
		{
			_root = Copy(t._root);
		}

		//赋值
		BSTree<K>& operator=(BSTree<K> t)
		{
			swap(_root, t._root);
			return *this;
		}

	private:

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

			return newTree;
		}

		void _Destroy(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			if (root->_left)
			{
				_Destroy(root->_left);
			}
			if (root->_right)
			{
				_Destroy(root->_right);
			}
			delete root;
			root = nullptr;
		}

		bool _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}
			if (root->_val < key)
			{
				return _FindR(root->_right, key);
			}
			else if (root->_val > key)
			{
				return _FindR(root->_left, key);
			}
			else
			{
				return true;
			}
		}

		bool _InsertR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				root = new Node(key);
				return true;
			}
			if (root->_val < key)
			{
				return _InsertR(root->_right, key);
			}
			else if (root->_val > key)
			{
				return _InsertR(root->_left, key);
			}
			else
			{
				return false;
			}
		}

		bool _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}
			if (root->_val < key)
			{
				return _EraseR(root->_right, key);
			}
			else if (root->_val > key)
			{
				return _EraseR(root->_left, key);
			}
			else
			{
				//1、左子树为空
				//2、右子树为空
				//3、左右子树都不为空
				if (root->_left == nullptr)
				{
					Node* del = root;
					root = root->_right;
					delete del;
					del = nullptr;
				}
				else if (root->_right == nullptr)
				{
					Node* del = root;
					root = root->_left;
					delete del;
					del = nullptr;
				}
				else
				{
					Node* leftMax = root->_left;
					while (leftMax->_right)
					{
						leftMax = leftMax->_right;
					}
					swap(leftMax->_val, root->_val);
					_EraseR(root->_left, key);
				}

				return true;
			}
		}

		void _InOrder(Node* _root)
		{
			if (_root == nullptr)
			{
				return;
			}
			_InOrder(_root->_left);
			cout << _root->_val << " ";
			_InOrder(_root->_right);
		}

	private:
		Node* _root;
	};


	void TestBSTree1()
	{
		int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
		BSTree<int> t;
		for (auto e : a)
		{
			t.Insert(e);
		}

		t.InOrder();

		t.Erase(4);
		t.InOrder();

		t.Erase(6);
		t.InOrder();

		t.Erase(7);
		t.InOrder();

		t.Erase(3);
		t.InOrder();

		for (auto e : a)
		{
			t.Erase(e);
			t.InOrder();
		}

	}

	void TestBSTree2()
	{
		int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
		BSTree<int> t1;
		for (auto e : a)
		{
			t1.InsertR(e);
		}

		BSTree<int> t;
		t = t1;

		t.InOrder();

		t.EraseR(4);
		t.InOrder();

		t.EraseR(6);
		t.InOrder();

		t.Erase(7);
		t.InOrder();

		t.EraseR(3);
		t.InOrder();

		for (auto e : a)
		{
			t.EraseR(e);
			t.InOrder();
		}

	}
}

四、Key–Value模型的二叉搜索树的实现

其实Key–Value模型的二叉搜索树和Key模型的二叉搜索树基本上是一样的,只不过在树的节点中多存放一个value值,所以代码实现如下。


namespace key_value
{
	template <class K,class V>
	struct BSTreeNode
	{
		BSTreeNode<K,V>* _left;
		BSTreeNode<K,V>* _right;
		K _key;
		V _value;

		BSTreeNode(const K& key,const V& value)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
			,_value(value)
		{}
	};

	template <class K,class V>
	class BSTree
	{
		typedef BSTreeNode<K,V> Node;
	public:
		BSTree()
			:_root(nullptr)
		{}

		Node* 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 cur;
				}
			}

			return nullptr;
		}

		bool Insert(const K& key,const V& value)
		{
			if (_root == nullptr)
			{
				_root = new Node(key,value);
				return true;
			}

			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (key > cur->_key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (key < cur->_key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}
			Node* newNode = new Node(key, value);
			if (key < parent->_key)
			{
				parent->_left = newNode;
			}
			else
			{
				parent->_right = newNode;
			}
			return true;
		}

		bool Erase(const K& key)
		{
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (key > cur->_key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (key < cur->_key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//找到了
					if (cur->_left == nullptr)
					{
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (parent->_left == cur)
							{
								parent->_left = cur->_right;
							}
							else if (parent->_right == cur)
							{
								parent->_right = cur->_right;
							}
						}

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

					}
					else
					{
						Node* parent = cur;
						Node* leftMax = cur->_left;
						while (leftMax->_right)
						{
							parent = leftMax;
							leftMax = leftMax->_right;
						}
						swap(leftMax->_key, cur->_key);
						swap(leftMax->_value, cur->_value);

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

						cur = leftMax;
					}

					delete cur;
					cur = nullptr;
					return true;
				}
			}

			return false;


		}

		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

		Node* FindR(const K& key)
		{
			return _FindR(_root, key);
		}

		bool InsertR(const K& key,const V& value)
		{
			return _InsertR(_root, key, value);
		}

		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}

	private:
		Node* _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
			{
				return nullptr;
			}
			if (root->_key < key)
			{
				return _FindR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _FindR(root->_left, key);
			}
			else
			{
				return root;
			}
		}

		bool _InsertR(Node*& root, const K& key,const V& value)
		{
			if (root == nullptr)
			{
				root = new Node(key, value);
				return true;
			}
			if (root->_key < key)
			{
				return _InsertR(root->_right, key, value);
			}
			else if (root->_key > key)
			{
				return _InsertR(root->_left, key, value);
			}
			else
			{
				return false;
			}
		}

		bool _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}
			if (root->_key < key)
			{
				return _EraseR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _EraseR(root->_left, key);
			}
			else
			{
				//1、左子树为空
				//2、右子树为空
				//3、左右子树都不为空
				if (root->_left == nullptr)
				{
					Node* del = root;
					root = root->_right;
					delete del;
					del = nullptr;
				}
				else if (root->_right == nullptr)
				{
					Node* del = root;
					root = root->_left;
					delete del;
					del = nullptr;
				}
				else
				{
					Node* leftMax = root->_left;
					while (leftMax->_right)
					{
						leftMax = leftMax->_right;
					}
					swap(leftMax->_val, root->_val);
					swap(leftMax->_value, root->_value);

					_EraseR(root->_left, key);
				}

				return true;
			}
		}

		void _InOrder(Node* _root)
		{
			if (_root == nullptr)
			{
				return;
			}
			_InOrder(_root->_left);
			cout << _root->_key << ":" << _root->_value << endl;
			_InOrder(_root->_right);
		}

	private:
		Node* _root;
	};

	void TestBSTree1()
	{
		string arr[] = { "苹果","苹果","香蕉","雪梨","草莓" };
		BSTree<string,int> t;
		for (const auto e : arr)
		{
			auto ret = t.FindR(e);
			if (ret == nullptr)
			{
				t.InsertR(e, 1);
			}
			else
			{
				ret->_value++;
			}
		}
		t.InOrder();

	}

	void TestBSTree2()
	{
		BSTree<string, string> dict;
		dict.InsertR("sort", "排序");
		dict.InsertR("left", "左边");
		dict.InsertR("right", "右边");
		
		string str;
		while (cin >> str)
		{
			auto ret = dict.FindR(str);
			if (ret)
			{
				cout << ret->_key << ":" << ret->_value << endl;
			}
			else
			{
				cout << "无此单词" << endl;
			}
		}
	}

}

五、Key模型和Key–Value模型二叉搜索树有的应用实例

key模型:判断数据在不在,例如学校门禁系统,扫脸确认该学生在不在学校的教务信息管理系统中。
key-value:判断在不在,在的同时把与之相关的绑定的信息返回,例如英译中的字典,统计每种书本的数目等。

六、二叉搜索树的性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:
在这里插入图片描述

最优情况下,二叉搜索树为完全二叉树(或者接近完全二叉树),其平均比较次数为:logN
在这里插入图片描述

最差情况下,二叉搜索树退化为单支树(或者类似单支),其平均比较次数为:N

所以二叉搜索树的性能并不能得到很好的保证,我们该如何改进这棵树,使它避免在极端情况下退化成链表呢?
就是在接下来的AVL树和红黑树中实现。

好啦,以上就是今天想要跟大家分享的全部内容啦,你学会了嘛?如果感觉有所收获,你就点一下小心心,点点关注呗,后期还会持续更新C++相关的知识哦,我们下期见!!!!!

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值