【C++进阶】二叉搜索树

二叉搜索树概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树
在这里插入图片描述

二叉搜索树操作

在这里插入图片描述

  1. 二叉搜索树的查找
    a、从根开始比较,查找,比根大往右边走查找,比根小往左边走查找。
    b、最多查找高度次,走到到空,还没找到,这个值不存在。
  2. 二叉搜索树的插入
    插入的具体过程如下:
    a. 树为空,则直接新增节点,赋值给root指针
    b. 树不空按二叉搜索树性质查找插入位置,插入新节点
  3. 二叉搜索树的删除
    首先查找元素是否在二叉搜索树中,如果不在,则返回, 否则要删除的结点可能分下面四种情况:
    a. 要删除的结点无孩子结点
    b. 要删除的结点只有左孩子结点
    c. 要删除的结点只有右孩子结点
    d. 要删除的结点有左、右孩子结点

    看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程
    如下:
    情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点–直接删除
    情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点–直接删除
    情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,再来处理该结点的删除问题–替换法删除

二叉搜索树的实现

每个节点的结构

在这里插入图片描述

插入

在这里插入图片描述

查找

在这里插入图片描述

删除

在这里插入图片描述
因为代码太长,无法画图,那么注释分析一下。
在这里插入图片描述

二叉搜索树的所有代码(包括测试)

版本一

#pragma once
namespace lzf
{
	template<class K>
	struct BinarySearchTreeNode
	{
		K _key;
		BinarySearchTreeNode<K>* left;
		BinarySearchTreeNode<K>* right;

		BinarySearchTreeNode(const K& key)
			:_key(key)
			,left(nullptr)
			,right(nullptr)
		{}
	};

	template<class K>
	class BinarySearchTree
	{
	public:
		typedef BinarySearchTreeNode<K> Node;
		BinarySearchTree()
			:_root(nullptr)
		{}
		bool Insert(const K& key)
		{
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}
			Node* prev = nullptr;
			Node* cur = _root;
			
			while (cur)
			{
				if (cur->_key > key)
				{
					prev = cur;
					cur = cur->left;
				}
				else if(cur -> _key < key)
				{
					prev = cur;
					cur = cur->right;
				}
				else
				{
					return false;
				}
			}

			if (prev->_key > key)
			{
				prev->left = new Node(key);
			}
			else
			{
				prev->right = new Node(key);
			}
			return true;

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

			return false;
		}
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}
		bool Erase(const K& key)
		{
			if (_root == nullptr)
				return false;
			Node* cur = _root;
			Node* prev = _root;
			//cur为空条件结束,说明没有找到要删除的值
			while (cur)
			{
				//如果要删除值,比该节点的值小
				if (cur->_key > key)
				{
					//记录父母
					prev = cur;
					//往左路再找
					cur = cur->left;
				} 
				//如果要删除值,比该节点的值小
				else if (cur->_key < key)
				{
					//记录父母
					prev = cur;
					//往左路再找
					cur = cur->right;
				}
				else
				{
					//找到了
					//该节点左孩子或者有右孩子为空的情况又或者全部为空的情况
					if (cur->left == nullptr || cur->right == nullptr)
					{
						//如果要删除的就是根节点
						if (_root == cur)
						{
							//如果左孩子不为空,把左孩子变为根
							if (cur->left == nullptr)
							{
								_root = cur->right;
							}
							//如果右孩子不为空,把右孩子变为根
							else
							{
								_root = cur->left;
							}
						}
						//如果要删除的是根节点以外的节点
						else
						{
							//如果该节点是父母节点的左孩子
							if (prev->left == cur)
							{
								//如果该节点的左孩子不为空,直接让父母指向该节点的左孩子
								if (cur->left == nullptr)
								{
									prev->left = cur->right;
								}
								//否则,直接让父母指向该节点的右孩子
								else
								{
									prev->left = cur->left;
								}
							}
							//如果该节点是父母节点的右孩子
							else
							{
								//如果该节点的左孩子不为空,直接让父母指向该节点的左孩子
								if (cur->left == nullptr)
								{
									prev->right = cur->right;
								}
								//否则,直接让父母指向该节点的右孩子
								else
								{
									prev->right = cur->left;
								}
							}
							//删除该节点,并返回删除成功
							delete cur;
							return true;
						}
					}
					//该节点的左右孩子均存在
					else
					{
						//记录根的左子树最小值节点
						Node* min = _root->right;
						//记录根的左子树最小值节点的父母
						Node* minprev = _root;

						//从根的右子树开始,寻找最小值节点
						while (min->left)
						{
							minprev = min;
							min = min->left;
						}
						//找到了,交换两节点的值
						swap(cur->_key, min->_key);

						//判断该节点是父母节点的左孩子还是右孩子,然后把该节点的右孩子给父母
						//记住这里的min一定只有右孩子,因为它的最小值
						if (minprev->left == min)
							minprev->left = min->right;
						else
							minprev->right = min->right;

						//删除该节点,并返回删除成功
						delete min;
						return true;
					}
				}
			}

			//走到这里说明没有找到要删除的值,直接返回false
			return false;
		}

		bool InsertR(const K& key)
		{
			return _InserR(_root, key);
		}
		bool FindR(const K& key)
		{
			return _FindR(_root, key);
		}
		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}
	private:
		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->left);
			cout << root->_key;
			_InOrder(root->right);
		}
		bool _InserR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				root = new Node(key);
				return true;
			}

			if (root->_key < key)
			{
				return _InserR(root->right, key);
			}
			else if (root->_key > key)
			{
				return _InserR(root->left, key);
			}
			else
			{
				return false;
			}
		}
		bool _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
			{
				return false;
			}

			if (root->_key < key)
			{
				return _FindR(root->right, key);
			}
			else if (root->_key > key)
			{
				return _FindR(root->left, key);
			}
			else
			{
				return true;
			}
		}
		bool _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
				return false;
			if (root->_key > key)
			{
				return _EraseR(root->left, key);
			}
			else if (root->_key < key)
			{
				return _EraseR(root->right, key);
			}
			else
			{
				Node* del = root;
				if (root->left == nullptr)
				{
					root = root->right;
				}
				else if (root->right == nullptr)
				{
					root = root->left;
				}
				else
				{
					Node* min = root->right;
					while (min->left)
					{
						min = min->left;
					}
					swap(root->_key, min->_key);

					return _EraseR(root->right, key);
				}

				delete del;
				return true;
			}
		}
	private:
		Node* _root;
	};

	void TestBinarySearchTree1()
	{
		BinarySearchTree<int> t;
		int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
		for (auto e : a)
		{
			t.InsertR(e);
		}
		t.InOrder();
		/*cout << t.Find(8) << endl;
		cout << t.Find(9) << endl;
		cout << t.Find(10) << endl;*/
		/*t.Erase(4);
		t.InOrder();
		t.Erase(7);
		t.InOrder();
		t.Erase(5);
		t.InOrder();
		t.Erase(0);
		t.InOrder();
		t.Erase(1);
		t.InOrder();
		t.Erase(2);
		t.InOrder();
		t.Erase(3);
		t.InOrder();
		t.Erase(6);
		t.InOrder(); 
		t.Erase(8);
		t.InOrder();
		t.Erase(9);
		t.InOrder();*/
		/*cout << t.Find(8) << endl;
		cout << t.Find(9) << endl;
		cout << t.Find(10) << endl;*/
		t.EraseR(4);
		t.InOrder();
		t.EraseR(7);
		t.InOrder();
		t.EraseR(5);
		t.InOrder();
		t.EraseR(0);
		t.InOrder();
		t.EraseR(1);
		t.InOrder();
		t.EraseR(2);
		t.InOrder();
		t.EraseR(3);
		t.InOrder();
		t.EraseR(6);
		t.InOrder();
		t.EraseR(8);
		t.InOrder();
		t.EraseR(9);
		t.InOrder();
	}
}

版本二

namespace lzh
{
	template<class K,class V>
	struct BinarySearchTreeNode
	{
		K _key;
		V _value;
		BinarySearchTreeNode<K,V>* left;
		BinarySearchTreeNode<K,V>* right;

		BinarySearchTreeNode(const K& key,const V& value)
			:_key(key)
			,_value(value)
			, left(nullptr)
			, right(nullptr)
		{}
	};

	template<class K,class V>
	class BinarySearchTree
	{
	public:
		typedef BinarySearchTreeNode<K,V> Node;
		BinarySearchTree()
			:_root(nullptr)
		{}
		
		
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}
		

		bool InsertR(const K& key,const V& value)
		{
			return _InserR(_root, key, value);
		}
		Node* FindR(const K& key)
		{
			return _FindR(_root, key);
		}
		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}
	private:
		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->left);
			cout << root->_key << " " << root->_value << endl;
			_InOrder(root->right);
		}
		bool _InserR(Node*& root, const K& key, const V& value)
		{
			if (root == nullptr)
			{
				root = new Node(key, value);
				return true;
			}

			if (root->_key < key)
			{
				return _InserR(root->right, key, value);
			}
			else if (root->_key > key)
			{
				return _InserR(root->left, key, value);
			}
			else
			{
				return false;
			}
		}
		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 _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
				return false;
			if (root->_key > key)
			{
				return _EraseR(root->left, key);
			}
			else if (root->_key < key)
			{
				return _EraseR(root->right, key);
			}
			else
			{
				Node* del = root;
				if (root->left == nullptr)
				{
					root = root->right;
				}
				else if (root->right == nullptr)
				{
					root = root->left;
				}
				else
				{
					Node* min = root->right;
					while (min->left)
					{
						min = min->left;
					}
					swap(root->_key, min->_key);

					return _EraseR(root->right, key);
				}

				delete del;
				return true;
			}
		}
	private:
		Node* _root;
	};
	void Test_BinarySearchTree1()
	{
		// 字典KV模型
		BinarySearchTree<string, string> dict;
		dict.InsertR("sort", "排序");
		dict.InsertR("left", "左边");
		dict.InsertR("right", "右边");
		dict.InsertR("map", "地图、映射");
		//...
		dict.InOrder();
		dict.EraseR("left");
		dict.EraseR("sort");
		dict.EraseR("right");
		dict.EraseR("map");
		string str;
		while (cin >> str)
		{
			BinarySearchTreeNode<string, string>* ret = dict.FindR(str);
			if (ret)
			{
				cout << "对应中文解释:" << ret->_value << endl;
			}
			else
			{
				cout << "无此单词" << endl;
			}
		}
	}
	void Test_BinarySearchTree2()
	{
		// 统计水果出现次数
		string arr[] = { "苹果", "西瓜","草莓", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉" };
		BinarySearchTree<string, int> countTree;
		for (auto& str : arr)
		{
			//BSTreeNode<string, int>* ret = countTree.Find(str);
			auto ret = countTree.FindR(str);
			if (ret != nullptr)
			{
				ret->_value++;
			}
			else
			{
				countTree.InsertR(str, 1);
			}
		}

		countTree.InOrder();
	}
}

test.cpp

#include<iostream>
using namespace std;
#include"BinarySearchTree.h"
int main()
{
	//lzf::TestBinarySearchTree1();
	//lzh::Test_BinarySearchTree1();
	lzh::Test_BinarySearchTree2();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值