【C++从0到王者】第二十八站:二叉搜索树的应用

文章目录

前言

二叉搜索树的在现实世界的应用很广泛,比如Key模型,Key-Value模型就是常见的两种的模型

一、Key模型

K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。即就是判断key在不在就可以了。

比如:门禁系统,小区车辆出入系统等等

给一个单词word,判断该单词是否拼写正确,具体方式如下:

以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树

在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

我们前面文章中所完成的二叉搜索树就是key模型的二叉搜身树

二、Key/Value模型

Key/Value每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见:比如商场的车辆出入系统(计时付费),高铁实名制车票系统等

比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;

再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是<word, count>就构成一种键值对

现在就让我们来实现一个key-value模型的二叉搜索树。

cpp 复制代码
#pragma once

template<class K, class V>
struct BSTreeNode
{
	BSTreeNode(const K& key = K(), const V& val = V())
		:_key(key)
		,_val(val)
		,_left(nullptr)
		,_right(nullptr)
	{}
	K _key;
	V _val;
	BSTreeNode<K,V>* _left;
	BSTreeNode<K,V>* _right;
};

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

	BSTree(const BSTree<K,V>& t)
	{
		_root = Copy(t._root);
	}

	~BSTree()
	{
		_Destory(_root);
	}

	BSTree<K,V>& operator=(BSTree<K,V> t)
	{
		std::swap(_root, t._root);
		return *this;
	}

	bool Insert(const K& key,const V& val)
	{
		if (_root == nullptr)
		{
			_root = new Node(key,val);
			return true;
		}
		else
		{
			Node* parent = _root;
			Node* cur = _root;
			while (cur != nullptr)
			{
				if (cur->_key == key)
				{
					return false;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					parent = cur;
					cur = cur->_right;
				}
			}
			cur = new Node(key,val);
			if (parent->_key > key)
			{
				parent->_left = cur;
			}
			else if (parent->_key < key)
			{
				parent->_right = cur;
			}
			return true;
		}
	}
	void InOrder()
	{
		_InOrder(_root);
	}

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

	bool Erase1(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				if (parent == nullptr)
				{
					if (cur->_left == nullptr)
					{
						_root = cur->_right;
						delete cur;
						return true;
					}
					else if (cur->_right == nullptr)
					{
						_root = cur->_left;
						delete cur;
						return true;
					}
					else
					{
						Node* leftMaxParent = cur;
						Node* leftMax = cur->_left;
						if (leftMax->_right == nullptr)
						{
							leftMax->_right = cur->_right;
							delete cur;
							_root = leftMax;
							return true;
						}
						while (leftMax->_right)
						{
							leftMaxParent = leftMax;
							leftMax = leftMax->_right;
						}
						std::swap(leftMax->_key, cur->_key);
						std::swap(leftMax->_val, cur->_val);

						leftMaxParent->_right = leftMax->_left;
						delete leftMax;
						leftMax = nullptr;
						return true;
					}
				}
				if (parent->_left == cur)
				{
					if (cur->_left == nullptr)
					{
						parent->_left = cur->_right;
						delete cur;
						return true;
					}
					else if (cur->_right == nullptr)
					{
						parent->_left = cur->_left;
						delete cur;
						return true;
					}
					else 
					{
						Node* leftMaxParent = cur;
						Node* leftMax = cur->_left;
						if (leftMax->_right == nullptr)
						{
							leftMax->_right = cur->_right;
							delete cur;
							parent->_left = leftMax;
							return true;
						}
						while (leftMax->_right)
						{
							leftMaxParent = leftMax;
							leftMax = leftMax->_right;
						}
						std::swap(leftMax->_key, cur->_key);
						std::swap(leftMax->_val, cur->_val);

						leftMaxParent->_right = leftMax->_left;
						delete leftMax;
						leftMax = nullptr;
						return true;
					}
				}
				else
				{
					if (cur->_left == nullptr)
					{
						parent->_right = cur->_right;
						delete cur;
						return true;
					}
					else if (cur->_right == nullptr)
					{
						parent->_right = cur->_left;
						delete cur;
						return true;
					}
					else
					{
						Node* leftMaxParent = cur;
						Node* leftMax = cur->_left;
						if (leftMax->_right == nullptr)
						{
							leftMax->_right = cur->_right;
							delete cur;
							parent->_right = leftMax;
							return true;
						}
						while (leftMax->_right)
						{
							leftMaxParent = leftMax;
							leftMax = leftMax->_right;
						}
						std::swap(leftMax->_key, cur->_key);
						std::swap(leftMax->_val, cur->_val);

						leftMaxParent->_right = leftMax->_left;
						delete leftMax;
						leftMax = nullptr;
						return true;
					}
				}
			}
		}
		return false;
	}

	bool Erase2(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			if (cur->_key > key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (cur->_key < key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				if (cur->_left == nullptr)
				{
					if (parent == nullptr)
					{
						_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 (parent == nullptr)
					{
						_root = cur->_left;
					}
					else if (parent->_left == cur)
					{
						parent->_left = cur->_left;
					}
					else if (parent->_right = cur)
					{
						parent->_right = cur->_left;
					}
				}
				else
				{
					Node* leftMax = cur->_left;
					Node* leftMaxParent = cur;
					while (leftMax->_right)
					{
						leftMaxParent = leftMax;
						leftMax = leftMax->_right;
					}
					std::swap(cur->_key, leftMax->_key);
					std::swap(cur->_val, leftMax->_val);

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

					cur = leftMax;
				}
				delete cur;
				return true;
			}
		}
	}

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

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

	bool EraseR(const K& key)
	{
		return _EraseR(_root, key);
	}
private:
	Node* Copy(Node* root)
	{
		if (root == nullptr)
		{
			return nullptr;
		}
		Node* Copyroot = new Node(root->_key, root->val);
		Copyroot->_left = Copy(root->_left);
		Copyroot->_right = Copy(root->_right);

		return Copyroot;
	}

	void _Destory(Node*& root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Destory(root->_left);
		_Destory(root->_right);
		delete root;
		root == nullptr;
	}
	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
		{
			Node* del = root;
			if (root->_left == nullptr)
			{
				root = root->_right;
			}
			else if (root->_right == nullptr)
			{
				root = root->_left;
			}
			else
			{
				Node* leftMax = root->_left;
				while (leftMax->_right)
				{
					leftMax = leftMax->_right;
				}
				std::swap(leftMax->_key, root->_key);
				std::swap(leftMax->_val, root->_val);

				return _EraseR(root->_left, key);
			}
			delete del;
			return true;
		}
	}
	bool _InsertR(Node*& root, const K& key, const V& val)
	{
		if (root == nullptr)
		{
			root = new Node(key, val);
			return true;
		}
		if (root->_key < key)
		{
			return _InsertR(root->_right, key, val);
		}
		else if (root->_key > key)
		{
			return _InsertR(root->_left, key, val);
		}
		else
		{
			return false;
		}
	}
	Node* _FindR(Node* root, const K& key)
	{
		if (root == nullptr)
		{
			return nullptr;
		}
		if (root->_key == key)
		{
			return root;
		}
		else if (root->_key > key)
		{
			return _FindR(root->_left, key);
		}
		else
		{
			return  _FindR(root->_right, key);
		}
	}
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << " :" << root->_val << endl;
		_InOrder(root->_right);
	}
private:
	Node* _root;
};

如上就是我们的KV模型的二叉搜索树。我们可以使用如下的两个模型,就是我们的这棵树的应用

cpp 复制代码
void test1()
{
	BSTree<string, string> dic;
	dic.Insert("review", "复习");
	dic.Insert("product", "产品,产物");
	dic.Insert("education", "教育");
	dic.Insert("interfere", "干涉");
	cout << "请输入单词" << endl;

	string str;
	while (cin >> str)
	{
		BSTreeNode<string, string>* ret = dic.Find(str);
		if (ret)
		{
			cout << ret->_val << endl;
		}
		else
		{
			cout << "无此单词" << endl;
			cout << "请你添加单词的意思:" << endl;
			string str_val;
			cin >> str_val;
			dic.Insert(str, str_val);
		}
		cout << "请输入单词" << endl;
	}
}

如上就是一个查找单词的模型,可以帮我们快速找出单词的意思,如果没有,可以自行添加意思

如下所示是一个水果计数的应用

cpp 复制代码
void test2()
{
	string arr[] = { "苹果", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜","苹果", "香蕉", "苹果", "香蕉" };
	BSTree<string, int> FruitCount;

	for (auto& e : arr)
	{
		BSTreeNode<string, int>* ret = FruitCount.Find(e);
		if (ret == nullptr)
		{
			FruitCount.Insert(e, 1);
		}
		else
		{
			ret->_val++;
		}
	}

	FruitCount.InOrder();

}

总结

本节主要讨论了二叉搜索树的两种应用。希望能对大家带来帮助

相关推荐
smj2302_7968265230 分钟前
用枚举算法解决LeetCode第3348题最小可整除数位乘积II
python·算法·leetcode
爱吃生蚝的于勒37 分钟前
C语言最简单的扫雷实现(解析加原码)
c语言·开发语言·学习·计算机网络·算法·游戏程序·关卡设计
Ai 编码助手40 分钟前
Go语言 实现将中文转化为拼音
开发语言·后端·golang
姆路40 分钟前
QT中使用图表之QChart绘制动态折线图
c++·qt
hummhumm42 分钟前
第 12 章 - Go语言 方法
java·开发语言·javascript·后端·python·sql·golang
hummhumm42 分钟前
第 8 章 - Go语言 数组与切片
java·开发语言·javascript·python·sql·golang·database
何曾参静谧42 分钟前
「QT」文件类 之 QDir 目录类
开发语言·qt
何曾参静谧44 分钟前
「QT」文件类 之 QTemporaryDir 临时目录类
开发语言·qt
杜杜的man1 小时前
【go从零单排】Directories、Temporary Files and Directories目录和临时目录、临时文件
开发语言·后端·golang
qq_308957471 小时前
Gin 框架入门(GO)-1
开发语言·golang·gin