c++:二叉搜索树BinarySortTree

二叉搜索树BinarySortTree

1.二叉搜索树概念

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

它的左右子树也分别为二叉搜索树
如图所示
在这里插入图片描述

二叉搜索树最大的功能便是搜索;一般来讲它比顺序表以链表的搜索时间复杂度要低;但是在极端条件下,它和顺序表、链表的时间复杂度相同。
当是满二叉树时,若搜索一个值,最多只需要二叉树的层数次;时间复杂度O(logN)。
在这里插入图片描述
当二叉树为下图结构时,若找“9”,便要遍历所有节点,时间复杂度最大,为O(N)。
在这里插入图片描述

2.二叉搜索树操作

(1)查找

在这里插入图片描述

(2)插入节点

插入的具体过程如下:
a. 树为空,则直接插入
在这里插入图片描述
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
从根节点开始,若插入的值小于根节点,便让根节点的左孩子成为新的父亲;若插入的值大于根节点,便让根节点的右孩子成为新的父亲;以此类推,直到正确的插入数据。
在这里插入图片描述

(3)删除节点

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:
a. 要删除的结点无孩子结点:删除后使其父亲节点指向nullptr;
b. 要删除的结点只有左孩子结点:删除后使其父亲结点指向其右孩子结点;
c. 要删除的结点只有右孩子结点:删除后使其父亲结点指向其左孩子结点;
d. 要删除的结点有左、右孩子结点:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中;然后对右子树中序下的第一个结点进行删除。

看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:

3.二叉搜索树的代码实现

(1)功能实现

#pragma once
#include<iostream>
#include<vector>
using namespace std;

template<class K>
struct BSTNode 
{
	K _key;//所存储的数据
	struct BSTNode<K>* _left;
	struct BSTNode<K>* _right;
	BSTNode(const K& key)
		:_key(key)
		,_left(nullptr)
		,_right(nullptr)
	{}
};

template<class K>
class BSTree
{
	typedef BSTNode<K> Node;
private:
	Node* _root = nullptr;
public:
	//遍历
	void InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		//中序遍历
		InOrder(root->_left);
		cout << root->_key << " ";
		InOrder(root->_right);
	}
	//重载一个无参函数,方便接口使用
	void InOrder()
	{
		InOrder(_root); 
		cout << endl;
	}
	//插入
	bool Insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
		}
		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);
		if (key > parent->_key)
		{
			parent->_right = cur;
		}
		else 
		{
			parent->_left = cur;
		}
	}
	//查找
	Node* Find(const K& key)
	{
		cout << "WANT FIND:" << key << endl;
		Node* cur = _root;
		while (cur)
		{
			if (key > cur->_key)
			{
				cur = cur->_right;
			}
			else if (key < cur->_key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		cout << "NOT FIND" << endl;
		return nullptr;
	}
	//删除节点
	bool Erase(const K& key)
	{
		cout << "ERASE:" << key << endl;
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (key > cur->_key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (key < cur->_key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//找到了,准备删除该节点
				//左为空||左右均为空结合讨论
				if (cur->_left == nullptr)
				{
					if (cur == _root)
						_root = cur->_right;
					else
					{
						if (cur == parent->_left)
							parent->_left = cur->_right;
						else
							parent->_right = cur->_right;
					}
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
						_root = cur->_left;
					else
					{
						if (cur == parent->_left)
							parent->_left = cur->_left;
						else
							parent->_right = cur->_left;
					}
					delete cur;
				}
				else
				{
					//subMin的父亲节点
					Node* subMinParent = cur;
					//右子树中寻找中序下的第一个节点subMin
					Node* subMin = cur->_right;
					while (subMin->_left)
					{
						subMinParent = subMin;
						subMin = subMin->_right;
					}
					cur->_key = subMin->_key;
					//subMin左孩子一定为空
					//考虑subMinParent可能为要删除的节点
					if (subMin == subMinParent->_left)
					{
						subMinParent->_left = subMin->_right;
					}
					else
					{
						subMinParent->_right = subMin->_right;
					}
					delete subMin;
				}
				return true;
			}
		}
		cout << "ERASE ERROR" << endl;
		return false;
	}
};

(2)测试

#include "BSTree.h"
using namespace std;
void BSTreeTest1()
{
	//插入节点
	BSTree<int> i;
	i.Insert(5);
	i.Insert(6);
	i.Insert(7);
	i.Insert(8);
	i.Insert(4);
	i.Insert(3);
	i.Insert(2);
	i.Insert(1);
	i.Insert(9);
	i.InOrder();
	cout << endl;
	//寻找节点
	BSTNode<int>* ret1 = i.Find(6);
	if (ret1)
	{
		cout << "FIND IT!" << endl;
	}
	BSTNode<int>* ret2 = i.Find(0);
	if (ret2)
	{
		cout << "FIND IT!" << endl;
	}
	cout << endl;

	//删除节点
	i.Erase(0);
	i.Erase(5);
	i.Erase(1);
	i.Erase(9);
	i.InOrder();
}

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

运行截图
在这里插入图片描述

2.4 二叉搜索树的应用

1. K模型

即为上述代码所实现的模型

功能:
a.查找在不在;
b.排序&&去重

K模型即只有Key作为关键码;节点结构中只需要存储Key即可,Key即为需要搜索到的值。
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
以单词集合中的每个单词作为key,构建一棵二叉搜索树在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

2. KV模型

每一个关键码key,都有与之对应的值Value;即<Key, Value>的键值对。

功能:
a.查找在不在;
b.排序&&去重
c.通过key查找value:比如字典
d.统计次数

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

实现一个简单的英汉词典dict,可以通过英文找到与其对应的中文,具体实现方式如下:
<word, chinese>为键值对构造二叉搜索树,查询英文单词时,只需给出英文单词,就可快速找到与其对应的中文。

3.KV模型的代码实现

代码逻辑完全相同,只需要添加一个新的值value,与key形成键值对

(1)功能实现
#pragma once
#pragma once
#include<iostream>
#include<vector>
using namespace std;

template<class K, class V>
struct BSTNodeKV
{
	const K _key;//所存储的数据
	V _value;
	struct BSTNodeKV<K, V>* _left;
	struct BSTNodeKV<K, V>* _right;
	BSTNodeKV(const K& key, const V& value)
		:_key(key)
		, _value(value)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

template<class K, class V>
class BSTreeKV
{
	typedef BSTNodeKV<K, V> Node;
private:
	Node* _root = nullptr;
public:
	//遍历
	void InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		//中序遍历
		InOrder(root->_left);
		cout << root->_key << ":"<<root->_value<<" ";
		InOrder(root->_right);
	}
	//重载一个无参函数,方便接口使用
	void InOrder()
	{
		InOrder(_root);
		cout << endl;
	}
	//插入
	bool Insert(const K& key, const V& value)
	{
		if (_root == nullptr)
		{
			_root = new Node(key, value);
		}
		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;
		}
	}
	//查找
	Node* Find(const K& key, const V& value)
	{
		//cout << "WANT FIND:" << key << endl;
		Node* cur = _root;
		while (cur)
		{
			if (key > cur->_key)
			{
				cur = cur->_right;
			}
			else if (key < cur->_key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur;
			}
		}
		//cout << "NOT FIND" << endl;
		return nullptr;
	}
	//删除节点
	bool Erase(const K& key, const V& value)
	{
		cout << "ERASE:" << key << endl;
		Node* parent = nullptr;
		Node* cur = _root;
		while (cur)
		{
			if (key > cur->_key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else if (key < cur->_key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else
			{
				//找到了,准备删除该节点
				//左为空||左右均为空结合讨论
				if (cur->_left == nullptr)
				{
					if (cur == _root)
						_root = cur->_right;
					else
					{
						if (cur == parent->_left)
							parent->_left = cur->_right;
						else
							parent->_right = cur->_right;
					}
					delete cur;
				}
				else if (cur->_right == nullptr)
				{
					if (cur == _root)
						_root = cur->_left;
					else
					{
						if (cur == parent->_left)
							parent->_left = cur->_left;
						else
							parent->_right = cur->_left;
					}
					delete cur;
				}
				else
				{
					//subMin的父亲节点
					Node* subMinParent = cur;
					//右子树中寻找中序下的第一个节点subMin
					Node* subMin = cur->_right;
					while (subMin->_left)
					{
						subMinParent = subMin;
						subMin = subMin->_right;
					}
					cur->_key = subMin->_key;
					//subMin左孩子一定为空
					//考虑subMinParent可能为要删除的节点
					if (subMin == subMinParent->_left)
					{
						subMinParent->_left = subMin->_right;
					}
					else
					{
						subMinParent->_right = subMin->_right;
					}
					delete subMin;
				}
				return true;
			}
		}
		cout << "ERASE ERROR" << endl;
		return false;
	}
	//通过key来找value
	V FindValue(const K& key)
	{
		cout << "WANT FIND:" << key <<":";
		Node* cur = _root;
		while (cur)
		{
			if (key > cur->_key)
			{
				cur = cur->_right;
			}
			else if (key < cur->_key)
			{
				cur = cur->_left;
			}
			else
			{
				return cur->_value;
			}
		}
		cout << "NOT FIND" << endl;
		exit(1);
	}
};
void BSTreeKVTest()
{
	BSTreeKV<string, string> dict;
	dict.Insert("banana", "香蕉");
	dict.Insert("ciname", "电影");
	dict.Insert("apple", "苹果");
	dict.Insert("dog", "狗");
	dict.Insert("string", "字符串");
	dict.Insert("sort", "排序");
	dict.InOrder();
	
	cout << dict.FindValue("sort") << endl;
	cout << dict.FindValue("dog") << endl;
	cout << dict.FindValue("aaaa") <<endl;
}
int main()
{
	/*BSTreeTest();
	cout << endl << endl << endl;*/
	BSTreeKVTest();
	return 0;
}
(2)测试
void BSTreeKVTest()
{
	//*******************************************************
	//插入与遍历
	BSTreeKV<string, string> dict;
	dict.Insert("banana", "香蕉");
	dict.Insert("ciname", "电影");
	dict.Insert("apple", "苹果");
	dict.Insert("dog", "狗");
	dict.Insert("string", "字符串");
	dict.Insert("sort", "排序");
	dict.InOrder();
	//*******************************************************
	//通过key寻找value
	cout << dict.FindValue("sort") << endl;
	cout << dict.FindValue("dog") << endl;
	cout << dict.FindValue("aaaa") <<endl;
	
	//********************************************************
	//计数功能
	string strArr[] = { "Aa","Aa" ,"Aa" ,"Bb","Bb" ,"Cc" };
	BSTreeKV<string, int>countTree;
	for (auto& str : strArr)
	{
		auto ret = countTree.Find(str);
		if (ret == nullptr)
		{
			countTree.Insert(str, 1);
		}
		else
		{
			ret->_value++;
		}
	}
	countTree.InOrder();
}
int main()
{
	/*BSTreeTest();
	cout << endl << endl << endl;*/
	BSTreeKVTest();
	return 0;
}

运行截图
在这里插入图片描述
在这里插入图片描述

  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值