二叉搜索树/二叉排序树/二叉查找树


在这里插入图片描述

1.概念

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

2.操作

  1. 二叉搜索树的查找
    a、从根开始,查找,比根大往右查,比根小往左查。
    b、最多查找高度次,走到空还没找到,这个值不存在。
  2. 二叉搜索树的插入
    插入的具体过程如下:
    a. 树为空,新增节点,赋值给root指针
    b. 树不空,查找插入位置,插入新节点
    3.二叉搜索树的删除
    查找元素是否在二叉搜索树中,不存在返回false。
    存在:目标结点
    a. 无子结点
    b. 只有左子结点
    c. 只有右子结点
    d. 有左、右子结点
    情况b:删除目标结点且使目标结点的父结点指向目标结点的左子结点–直接删除
    情况c:删除目标结点且使目标结点的父结点指向目标结点的右子结点–直接删除
    情况d:在目标结点的右子树中寻找中序下的第一个最小结点,用它的值填补到被删除节点中,再来处理该结点的删除问题–替换法删除

3.实现

3.1框架

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2BSTree.h

#pragma once

template<class K>
//树结点
struct BSTreeNode
{
	BSTreeNode<K>* _left;
	BSTreeNode<K>* _right;
	K _key;

	BSTreeNode(const K& key)
		:_left(nullptr)
		, _right(nullptr)
		, _key(key)
	{
	
	}
};
//二叉搜索树
//K模型
namespace K 
{
	template<class K>
	class BSTree
	{
		typedef BSTreeNode<K> Node;
	public:
		//构造函数
		/*
		BSTree()
			:_root(nullptr)
		{

		}
		*/
		BSTree() = default; // 制定强制生成默认构造
		//拷贝构造
		BSTree(const BSTree<K>& t)
		{
			_root = Copy(t._root);
		}
		//赋值重载
		BSTree<K>& operator=(BSTree<K> t)
		{
			swap(_root, t._root);
			return *this;
		}
		//析构函数
		~BSTree()
		{
			Destroy(_root);
		}
		//插入 
		bool Insert(const K& key)
		{
			//根值插入
			if (_root == nullptr)
			{
				_root = new Node(key);
				return true;
			}

			//定位合适位置
			Node* parent = nullptr;
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}

			cur = new Node(key);
			//父子链接
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}

			return true;
		}
		//插入-递归版
		bool InsertR(const K& key)
		{
			return _InsertR(_root, key);
		}
		//查找
		bool Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key < key)
				{
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					cur = cur->_left;
				}
				else
				{
					return true;
				}
			}

			return false;
		}
		//查找-递归版
		bool FindR(const K& key)
		{
			return _FindR(_root, key);
		}
		//删除
		bool Erase(const K& key)
		{
			Node* cur = _root;
			Node* parent = nullptr;

			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					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
							{
								//父右接管目标右
								parent->_right = cur->_right;
							}
						}
						delete cur;
					}
					// 2、右为空
					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;
					}
					// 3、左右均有子结点
					else
					{
						//找右树最小节点/左树最大节点
						//一、右树最小节点
						//obj只能是 只有右节点或叶子 
						//找obj【右树最小结点】
						//Node* nannyDad = cur;
						//Node* nanny = cur->_right;
						//while (nanny->_left)
						//{
						//	nannyDad = nanny;
						//	nanny = nanny->_left;
						//}
						赋值
						//cur->_key = nanny->_key;
						obj在父左 obj的右给父左
						//if (nannyDad->_left == nanny)
						//{
						//	nannyDad->_left = nanny->_right;
						//}
						obj在父右 obj的右给父右
						//else
						//{
						//	nannyDad->_right = nanny->_right;
						//}
						//delete nanny;
						//二、左树最大结点
						//obj只能是 只有左节点或叶子 
						//找obj【左树最大结点】
						Node* nannyDad = cur;
						Node* nanny = cur->_left;
						while (nanny->_right)
						{
							nannyDad = nanny;
							nanny = nanny->_right;
						}
						//赋值
						cur->_key = nanny->_key;
						//obj在父左 obj的右给父左
						if (nannyDad->_left == nanny)
						{
							nannyDad->_left = nanny->_right;
						}
						//obj在父右 obj的右给父右
						else
						{
							nannyDad->_right = nanny->_right;
						}
						delete nanny;
					}

					return true;
				}
			}

			return false;
		}
		//删除-递归版
		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}
		//中序遍历
		//1.直接写调用时传_root传不过去 _root是private [可以用GetRoot()]
		//2._root又无法做缺省值:条件是全局变量 常量 静态变量 且无this指针【this->_root】
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}
	protected:

		//拷贝函数
		Node* Copy(Node* root)
		{
			if (root == nullptr)
				return nullptr;

			Node* newRoot = new Node(root->_key);
			newRoot->_left = Copy(root->_left);
			newRoot->_right = Copy(root->_right);
			return newRoot;
		}
		//销毁函数
		void Destroy(Node*& root)
		{
			if (root == nullptr)
				return;

			Destroy(root->_left);
			Destroy(root->_right);

			delete root;
			root = nullptr;
		}
		//查找-递归版
		bool _FindR(Node* root, const K& key)
		{
			if (root == nullptr)
				return false;

			if (root->_key == key)
				return true;

			if (root->_key < key)
				return _FindR(root->_right, key);
			else
				return _FindR(root->_left, key);
		}
		//插入-递归版
		bool _InsertR(Node*& root, const K& key)
		{
			if (root == nullptr)
			{
				//引用传参 root是上层root的left或right 直接链接 yyds
				root = new Node(key);
				return true;
			}

			if (root->_key < key)
			{
				return _InsertR(root->_right, key);
			}
			else if (root->_key > key)
			{
				return _InsertR(root->_left, key);
			}
			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
			{
				//记录root 
				Node* obj = root;
				//右为空
				if (root->_right == nullptr)
				{
					root = root->_left; //实际是上层的root与当前层的root左链接 下同
				}
				//左为空
				else if (root->_left == nullptr)
				{
					root = root->_right;
				}
				//左右都不空
				else
				{
					Node* nanny = root->_left;
					while (nanny->_right)
					{
						nanny = nanny->_right;
					}
					swap(root->_key, nanny->_key);
					//将找到的nanny与obj交换 然后传新树递归删除obj
					//【此时obj定为叶子节点-利用递归将删除一个有左右子结点的结点转换为删除一个叶子节点】
					return _EraseR(root->_left, key);
				}
				delete obj;
				return true;
			}
		}
		//中序遍历 
		void _InOrder(Node* root)
		{
			if (root == nullptr)
				return;

			_InOrder(root->_left);
			cout << root->_key << " ";
			_InOrder(root->_right);
		}
	private:
		Node* _root = nullptr;
	};
}
//KV模型
namespace KV
{
	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:
		//插入
		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 (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					return false;
				}
			}

			cur = new Node(key, value);
			// 链接
			if (parent->_key < key)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}

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

			return nullptr;
		}
		//删除
		bool Erase(const K& key)
		{
			Node* cur = _root;
			Node* parent = nullptr;

			while (cur)
			{
				if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_key > key)
				{
					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
							{
								//父右接管目标右
								parent->_right = cur->_right;
							}
						}
						delete cur;
					}
					// 2、右为空
					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;
					}
					// 3、左右均有子结点
					else
					{
						//找右树最小节点/左树最大节点
						//一、右树最小节点
						//obj只能是 只有右节点或叶子 
						//找obj【右树最小结点】
						//Node* nannyDad = cur;
						//Node* nanny = cur->_right;
						//while (nanny->_left)
						//{
						//	nannyDad = nanny;
						//	nanny = nanny->_left;
						//}
						赋值
						//cur->_key = nanny->_key;
						obj在父左 obj的右给父左
						//if (nannyDad->_left == nanny)
						//{
						//	nannyDad->_left = nanny->_right;
						//}
						obj在父右 obj的右给父右
						//else
						//{
						//	nannyDad->_right = nanny->_right;
						//}
						//delete nanny;
						//二、左树最大结点
						//obj只能是 只有左节点或叶子 
						//找obj【左树最大结点】
						Node* nannyDad = cur;
						Node* nanny = cur->_left;
						while (nanny->_right)
						{
							nannyDad = nanny;
							nanny = nanny->_right;
						}
						//赋值
						cur->_key = nanny->_key;
						//obj在父左 obj的右给父左
						if (nannyDad->_left == nanny)
						{
							nannyDad->_left = nanny->_right;
						}
						//obj在父右 obj的右给父右
						else
						{
							nannyDad->_right = nanny->_right;
						}
						delete nanny;
					}
					return true;
				}
			}
			return false;
		}

		//中序遍历
		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}

protected:
	//中序遍历
	void _InOrder(Node* root)
	{
		if (root == nullptr)
			return;

		_InOrder(root->_left);
		cout << root->_key << ":" << root->_value << endl;
		_InOrder(root->_right);
	}
	private:
		Node* _root = nullptr;
	};
}

3.3test.cpp

#define _CRT_SECURE_NO_WARNINGS 
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <array>
#include <time.h>
#include <queue>
using namespace std;

#include "BSTree.h"

//插入、遍历、删除
void TestBSTree()
{
	int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
	K::BSTree<int> t1;
	//插入建树
	for (auto e : a)
	{
		t1.Insert(e);
	}

	t1.InOrder();

	t1.Erase(4);
	t1.InOrder();

	t1.Erase(14);
	t1.InOrder();

	t1.Erase(3);
	t1.InOrder();

	t1.Erase(8);
	t1.InOrder();
}
//KV模型--简易字典
void TestBSTree2()
{
	KV::BSTree<string, string> Dictionary;
	Dictionary.Insert("sort", "排序");
	Dictionary.Insert("left", "左边");
	Dictionary.Insert("right", "右边");
	Dictionary.Insert("string", "字符串");
	Dictionary.Insert("insert", "插入");
	Dictionary.Insert("erase", "删除");

	string str;
	while (cin >> str)
	{
		auto ret = Dictionary.Find(str);
		if (ret)
		{
			cout <<str << ":" << ret->_value << endl;
		}
		else
		{
			cout << "无此单词" << endl;
		}
	}
}
//KV模型--水果统计树
void TestBSTree3()
{
	string arr[] = { "西瓜", "西瓜", "苹果", "西瓜", "苹果", "苹果", "西瓜", "苹果", "香蕉", "苹果", "香蕉", "梨" };

	KV::BSTree<string, int> countTree;
	for (auto str : arr)
	{
		//KV::BSTreeNode<string, int>* 
		auto ret = countTree.Find(str);
		if (ret == nullptr)
		{
			countTree.Insert(str, 1);
		}
		else
		{
			ret->_value++;
		}
	}

	countTree.InOrder();
}

int main()
{
	TestBSTree3();
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿猿收手吧!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值