C++实现二叉搜索树(Key模型和Key/value模型)

#pragma once
#include<iostream>
namespace K
{
	template<class K>
	struct BSTreeNode
	{
		BSTreeNode(const K& key)
		:left(nullptr)
		, right(nullptr)
		, _key(key)
		{}

		BSTreeNode<K>* left;
		BSTreeNode<K>* right;
		K _key;
	};

	template<class K>
	struct BSTree
	{

		typedef BSTreeNode<K> Node;

	public:
		BSTree()
			:_root(nullptr)
		{}


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

			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				parent = cur;
				if (cur->_key > key)
				{
					cur = cur->left;
				}
				else if (cur->_key < key)
				{
					cur = cur->right;
				}
				else
				{
					return false;
				}
			}
			cur = new Node(key);
			if (parent->_key > key)
			{
				parent->left = cur;
			}
			else
			{
				parent->right = cur;
			}
			return true;
		}


		//删除
		bool Earse(const K& key)
		{
			//1.找到要删的节点
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key > key)
				{
					parent = cur;
					cur = cur->left;
				}
				else if (cur->_key < key)
				{
					parent = cur;
					cur = cur->right;
				}
				else
				{
					//找到了,进行删除。	
					//(1)有一个字节点或者没有子节点
					if (cur->left == nullptr)
					{
						if (parent == nullptr)
						{
							_root = cur->right;
							return true;
						}

						Node* child = cur->right;
						if (parent->left == cur)
						{
							parent->left = child;
						}
						else
						{
							parent->right = child;
						}

						//记住一定要delete掉cur这个节点
						delete cur;
					}
					else if (cur->right == nullptr)
					{
						if (parent == nullptr)
						{
							_root = cur->left;
							return true;
						}

						Node* child = cur->left;
						if (parent->left == cur)
						{
							parent->left = child;
						}
						else
						{
							parent->right = child;
						}
						//记住一定要delete掉cur这个节点
						delete cur;
					}
					//(2)左孩子右孩子都有
					else
					{
						//1.先找到右子树的最小节点或者左子树的最大节点
						//(我这里找的是右子树的最小节点)
						//必须要有父亲才能删除
						Node* Min_parent = cur;
						Node* Min_right = cur->right;
						while (Min_right->left)
						{
							Min_parent = Min_right;
							Min_right = Min_right->left;
						}

						//2.进行替换
						cur->_key = Min_right->_key;

						//3.删除被替换的节点(一定是叶子节点或者只有一个子节点的节点)
						//为什么要判断呢?
						//因为有可能Min_Parent就是cur
						if (Min_parent->left == Min_right)
						{
							Min_parent->left = Min_right->right;
						}
						else
						{
							Min_parent->right = Min_right->right;
						}
						delete Min_right;
					}

					return true;
				}
			}
			//没有这个值,删除失败
			return false;
		}

		//中序遍历,为什么写一个子程序?
		//因为外面调用不到private的_root
		void InOrder()
		{
			_InOrder(_root);
		}

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

			_InOrder(root->left);
			cout << root->_key << " ";
			_InOrder(root->right);
		}

		//查找
		bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key == key)
				{
					return true;
				}
				else if (cur->_key > key)
				{
					cur = cur->left;
				}
				else
				{
					cur = cur->right;
				}
			}
			return false;
		}

		//递归版本
		//设置子函数的原因还有一样,外界无法访问到_root

		//1.插入
		bool InsertR(const K& key)
		{
			_InsertR(key, _root);
			return true;
		}

		//这里的引用用的很巧妙。
		//因为这里的root就是这棵树的节点,遇到空了就是可以进行插入了
		//直接进行new就完成了插入操作。
		bool _InsertR(const K& key, Node*& root)
		{
			if (root == nullptr)
			{
				root = new Node(key);
				return true;
			}

			if (root->_key > key)
			{
				return _InsertR(key, root->left);
			}
			else if (root->_key < key)
			{
				return _InsertR(key, root->right);
			}
			else
			{
				return false;
			}


		}

		//2.查找
		Node* FindR(const K& key)
		{
			return _FindR(key, _root);
		}

		Node* _FindR(const K& key, Node* root)
		{
			if (key == root->_key || key == nullptr)
			{
				return root;
			}

			if (root->_key > key)
			{
				_FindR(key, root->left);
			}

			if (root->_key < key)
			{
				_FindR(key, root->right);
			}
		}


		//3.删除
		bool EarseR(const K& key)
		{
			return _EarseR(key, _root);
		}

		//这里的参数也是引用很巧妙
		bool _EarseR(const K& key, Node*& root)
		{
			if (root == nullptr)
			{
				return false;
			}

			//先找到要删除的节点
			if (root->_key > key)
			{
				_EarseR(key, root->left);
			}
			else if (root->_key < key)
			{
				_EarseR(key, root->right);
			}
			else
			{
				//进行删除
				//先记录要删除的节点
				Node* del = root;
				if (root->left == nullptr)
				{
					//很巧妙,直接将root换成了另外一个不为空或者可能为空的子树。
					root = root->right;
					delete del;
				}
				else if (root->right == nullptr)
				{
					root = root->left;
					delete del;
				}

				//要删除节点的有两个的时候
				else
				{
					//
					Node* min_right = root->right;
					while (min_right->left)
					{
						min_right = min_right->left;
					}

					//交换两个节点的的值
					swap(root->_key, min_right->_key);

					//当交换之后,整颗树就不是二叉搜索树了,
					//所以我们要在这个节点的右节点去删除这个值的节点就是很巧妙
					_EarseR(key, root->right);

				}
			}
		}


	private:
		Node* _root;

	};


	void TestBSTree()
	{
		BSTree<int> b;
		int a[] = { 5, 3, 6, 2, 4, 7 };
		for (auto e : a)
		{
			b.InsertR(e);
		}

		b.EarseR(7);

		b.InOrder();

	}
}

namespace KV
{

	template<class K, class V>
	struct BSTreeNode
	{
		BSTreeNode(const K& key, const V& value)
		:left(nullptr)
		, right(nullptr)
		, _key(key)
		, _value(value)
		{}

		BSTreeNode<K, V>* left;
		BSTreeNode<K, V>* right;
		K _key;
		V _value;
	};

	template<class K, class V>
	struct BSTree
	{

		typedef BSTreeNode<K, V>  Node;

	public:
		BSTree()
			:_root(nullptr)
		{}


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

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


		//删除
		bool Earse(const K& key)
		{
			//1.找到要删的节点
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key > key)
				{
					parent = cur;
					cur = cur->left;
				}
				else if (cur->_key < key)
				{
					parent = cur;
					cur = cur->right;
				}
				else
				{
					//找到了,进行删除。	
					//(1)有一个字节点或者没有子节点
					if (cur->left == nullptr)
					{
						if (parent == nullptr)
						{
							_root = cur->right;
							return true;
						}

						Node* child = cur->right;
						if (parent->left == cur)
						{
							parent->left = child;
						}
						else
						{
							parent->right = child;
						}

						//记住一定要delete掉cur这个节点
						delete cur;
					}
					else if (cur->right == nullptr)
					{
						if (parent == nullptr)
						{
							_root = cur->left;
							return true;
						}

						Node* child = cur->left;
						if (parent->left == cur)
						{
							parent->left = child;
						}
						else
						{
							parent->right = child;
						}
						//记住一定要delete掉cur这个节点
						delete cur;
					}
					//(2)左孩子右孩子都有
					else
					{
						//1.先找到右子树的最小节点或者左子树的最大节点
						//(我这里找的是右子树的最小节点)
						//必须要有父亲才能删除
						Node* Min_parent = cur;
						Node* Min_right = cur->right;
						while (Min_right->left)
						{
							Min_parent = Min_right;
							Min_right = Min_right->left;
						}

						//2.进行替换
						cur->_key = Min_right->_key;
						cur->_value = Min_right->_value;

						//3.删除被替换的节点(一定是叶子节点或者只有一个子节点的节点)
						//为什么要判断呢?
						//因为有可能Min_Parent就是cur
						if (Min_parent->left == Min_right)
						{
							Min_parent->left = Min_right->right;
						}
						else
						{
							Min_parent->right = Min_right->right;
						}
						delete Min_right;
					}

					return true;
				}
			}
			//没有这个值,删除失败
			return false;
		}

		//中序遍历,为什么写一个子程序?
		//因为外面调用不到private的_root
		void InOrder()
		{
			_InOrder(_root);
		}

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

			_InOrder(root->left);
			cout << root->_key << ":";
			cout << root->_value << endl;
			_InOrder(root->right);
		}

		//查找
		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
				{
					cur = cur->right;
				}
			}
			return nullptr;
		}

	private:
		Node* _root;
	};

	//KV使用场景1:查找
	void TestBSTree1()
	{
		BSTree<string, string> dict;
		dict.Insert("left", "左");
		dict.Insert("right", "右");
		dict.Insert("sort", "排序");
		dict.Insert("map", "地图,映射");

		string str;
		
		while (cin >> str)
		{
			auto ret = dict.Find(str);
			if (ret)
			{
				cout << "对应中文解释是:" << ret->_value << endl;
			}
			else
			{
				cout << "查不到" << endl;
			}
		}
	}
	
	//KV使用场景2:统计次数
	void TestBSTree2()
	{
		string arr[] = { "苹果", "苹果", "苹果", "苹果", "苹果", "草莓", "草莓", "草莓", "香蕉" };
		BSTree<string, int> count_tree;
		for (auto& str : arr)
		{
			//BSTreeNode<string, int>* ret = count_tree.Find(str);
			auto ret = count_tree.Find(str);
			if (ret)
			{
				ret->_value++;
			}
			else
			{
				count_tree.Insert(str, 1);
			}
		}

		count_tree.InOrder();
	}

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值