[C++] Application of binary search tree

foreword

The essence of the binary search tree is also a binary tree, but because of its special data storage — 左子树的值都更小,右子树的值都更大, so in most cases, 查找更为高效. This blog will talk about two binary search trees 应用搜索的场景
, so without further ado, let's start today's study.

insert image description here

1. Key model

The essence of Key's model is actually 在不在a problem

  1. For example: 门禁系统. When we go in and out of the school, we may need to swipe the campus card. In fact, there is a chip in the campus card. After interacting with the access control, you can read your information. Then, if you find it, you are allowed to pass 拿着这个信息,去数据库中查找. Passage is allowed.
  2. Another example: 车库系统. If you have a parking space in this garage, then when you enter and exit the garage, the pole of the garage will be lifted directly to let you go. But if you don't have a parking space, you can still raise the pole when you enter the parking lot, but when you come out, you need to pay the parking fee to raise the pole. This also involves finding and matching information.

最普通的二叉搜索树就是Key的模型, 每个节点只存储一个数据, and its 实际意义就是那个数据的意义
For example, the following binary search tree, its meaning is the storage of integer numbers.
insert image description here
The code of the binary search tree Key model is in [C++] binary search tree

2. The model of Key_Value

The model of Key_Value is actually 映射关系, Key不再单纯只有Key的意义,其还对应了一个Value.
Just like a key, it is not only a key, but also a corresponding lock. Our student number is not only a series of numbers, it also corresponds to our information in the student information management system.

For example, if we want to complete a Chinese-English translation dictionary, we can use the Key_Value model. The Key we input is "sort", and the corresponding Value is "sort".

Let's briefly write the code for the Key_Value model of the binary search tree. In fact 基本框架和Key模型一样, it's just that the class template parameter has one more template parameter

//类模板,用于存储不同数据
	template<class K,class V>
	struct BinarySearchTree
	{
    
    
		BinarySearchTree<K,V>*_left;//左子树
		BinarySearchTree<K,V>*_right;//右子树
		K _key;//key值
		V _value;//value值

		//构造函数
		BinarySearchTree(const K&key,const V&value)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
			,_value(value)
		{
    
    }

		~BinarySearchTree()
		{
    
    
			_left = nullptr;
			_right = nullptr;
		}
	};


	template<class K,class V>
	class BSTree
	{
    
    
		typedef BinarySearchTree<K,V> Node;
	public:
		//析构
		~BSTree()
		{
    
    
			Destroy(_root);
			_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 (key > cur->_key)
					cur = cur->_right;
				else if (key < cur->_key)
					cur = cur->_left;
				else
					//相等则返回假
					return false;
			}

			//找到了要插入的位置
			cur = new Node(key,value);
			//链接
			if (key > parent->_key)
				parent->_right = cur;
			else
				parent->_left = cur;

			return true;
		}

		//中序遍历
		//因为二叉搜索树的特点,中序打印出来就是升序

		//实现封装
		void InOrder()
		{
    
    
			_InOrder(_root);
			cout << endl;
		}

		//查找
		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 Erase(const K&key)
		{
    
    
			//分成两类
			//左或者右为空(包括叶子结点)
			//左右孩子都有

			//首先先找节点
			Node*cur = _root;
			//记录父亲节点
			Node*parent = nullptr;

			while (cur)
			{
    
    
				//parent = 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 (parent->_left == cur)
								parent->_left = cur->_right;
							else
								parent->_right = cur->_right;
						}

						delete cur;
						cur = nullptr;

						return true;

					}  // 右为空
					else if (cur->_right == nullptr)
					{
    
    
						//还有可能删到根节点的一边为空(有点像歪脖子树)
						if (cur == _root)
							_root = cur->_left;
						else
						{
    
    
							//要判断父节点链接左还右
							if (parent->_left == cur)
								parent->_left = cur->_left;
							else
								parent->_right = cur->_left;
						}

						delete cur;
						cur = nullptr;

						return true;
					}
					else
					{
    
    
						//左右子树都不为空
						//找保姆
						//左子树的最大节点 or 右子树的最小节点  二者都可以
						//  最右节点             最左节点

						Node*pMinRight = cur;//右子树的最小节点的父节点
						Node*MinRight = cur->_right;//右子树的最小节点

						while (MinRight->_left)
						{
    
    
							pMinRight = MinRight;
							MinRight = MinRight->_left;
						}

						//直接赋值
						cur->_key = MinRight->_key;

						//判断父节点要链接左还是右
						if (pMinRight->_left == MinRight)
							pMinRight->_left = MinRight->_right;
						else
							pMinRight->_right = MinRight->_right;

						//删除MinRight,因为完成交换了
						delete MinRight;
						MinRight = nullptr;

						return true;
					}
				}
			}

			return false;
		}

	protected:

		//销毁二叉搜索树
		void Destroy(Node*root)
		{
    
    
			if (root == NULL)
				return;

			//先删除左右节点,再删除当前节点
			Destroy(root->_left);
			Destroy(root->_right);

			delete root;
			root = nullptr;
		}

		//因为要递归,所以要单独编写
		//注意此处不可以加缺省值_root,因为缺省值需要是常量
		void _InOrder(Node*root)
		{
    
    
			if (root == nullptr)
				return;

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

	private:
		Node*_root = nullptr;//根节点
	};

Let's take English-Chinese translation as an example to test
insert image description here
ctrl+z+回车可以正常结束这样的循环

conclusion

thanks for reading

If you think this article is helpful to you, you might as well like it to support the blogger, please, this is really important to me.
insert image description here

Guess you like

Origin blog.csdn.net/m0_72563041/article/details/130264731