C/C++ 进阶(4)二叉搜索树

个人主页:仍有未知等待探索-CSDN博客

专题分栏:C++

一、概念

二叉搜索树,又称二叉排序树(中序是有序的)。

性质

1、非空左子树的键值小于根节点的键值

2、非空右子树的键值大于根节点的键值

(空树也是二叉搜索树)

二、操作

查找

查找,从根节点开始比较键值大小,如果比根节点的键值小,进左子树;比根节点的键值大,进右子树,然后继续进行比较。

插入

和查找差不多,先找到要插入的位置,然后进行插入即可。

cpp 复制代码
// 要插入的值 val
void insert(const T& val)
{
    // 特判一下空树
	if (_root == nullptr)
	{
		node* tmp = new node(val);
		_root = tmp;
		return;
	}
    
    // 记得要记录一下插入位置的父节点
	node* parent = _root;
	node* cur = _root;
	while (cur)
	{
		if (cur->val > val)
		{
			parent = cur;
			cur = cur->left;
		}
		else
		{
			parent = cur;
			cur = cur->right;
		}
	}
	cur = new node(val);
	if (parent->val > val)
	{
		parent->left = cur;
	}
	else
	{
		parent->right = cur;
	}
}

删除

删除一个节点的情况比较复杂,分为四种情况。

a.删除的节点为叶子节点

如果要删除 13 这个叶子节点,我们只需要让 13 的父节点的左孩子指向nullptr。

如果要删除 7 这个叶子节点,我们需要让 7 的父节点的右孩子指向nullptr。

总结:让要删除节点的父节点的对应指针指向空。

对应指针:判断要删除的节点是其父节点的左孩子还是右孩子。如果是左孩子,父节点的左孩子指向空;如果是右孩子,父节点的右孩子指向空。

b.删除的节点只有左子树

如果要删除 14 这个节点,我们需要让 14 的父节点的对应指针指向 14 的左子树。

总结:让要删除节点的父节点的对应指针指向要删除节点的左子树。

c.删除的节点只有右子树

如果要删除 10 这个节点,我们需要让 10 的父节点指向 10 的右子树。

总结:让要删除节点的父节点的对应指针指向要删除节点的右子树。

d.删除的节点有左、右子树

对于这个这种情况,我们用替换法来进行删除。首先我们先找到要删除节点的右子树中的最小值,然后和要删除的节点进行值替换,最后我们要删除掉替换后的节点。

总结:先替换,然后删除替换后的节点(判断替换后的节点的类型,然后用对应的删除方法)

cpp 复制代码
void erase(const T& val)
{
	node* cur = _root;
	node* parent = _root;
	
	while (cur)
	{
		if (cur->val > val)
		{
			parent = cur;
			cur = cur->left;
		}
		else if (cur ->val < val)
		{
			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 if (parent->right == cur)
				{
					parent->right = cur->right;
				}
				delete cur;
			}
			else if(cur->right == nullptr)
			{
				if (cur == _root)
				{
					_root = cur->left;
				}
				else if (parent->left == cur)
				{
					parent->left = cur->left;
				}
				else if (parent->right == cur)
				{
					parent->right = cur->left;
				}
				delete cur;
			}
			else
			{
				node* tmp = cur->right;
				node* tp = cur;
				while (tmp->left)
				{
					tp = tmp;
					tmp = tmp->left;
				}
				swap(cur->val, tmp->val);
				
				// 交换完,就相当是删除tmp,tmp的特点是左子树为空
				// 也相当于是删除没有左子树的节点

				if (tp->left == tmp)
					tp->left = tmp->right;
				else
					tp->right = tmp->right;

				delete tmp;

			}
		}
	}
}

总代码

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

template<class T>
struct BSTN
{
	BSTN(const T& e)
		:left(nullptr)
		,right(nullptr)
		,val(e)
	{}
	BSTN<T>* left;
	BSTN<T>* right;
	T val;
};

template<class T>
class BST
{
	typedef BSTN<T> node;
public:
	BST()
		:_root(nullptr)
	{}
	void insert(const T& val)
	{
		if (_root == nullptr)
		{
			node* tmp = new node(val);
			_root = tmp;
			return;
		}
		node* parent = _root;
		node* cur = _root;
		while (cur)
		{
			if (cur->val > val)
			{
				parent = cur;
				cur = cur->left;
			}
			else
			{
				parent = cur;
				cur = cur->right;
			}
		}
		cur = new node(val);
		if (parent->val > val)
		{
			parent->left = cur;
		}
		else
		{
			parent->right = cur;
		}
	}
	void inorder()
	{
		_inorder(_root);
	}
	bool find(const T& val)
	{
		node* cur = _root;
		while (cur)
		{
			if (cur->val > val)
			{
				cur = cur->left;
			}
			else if (cur->val < val)
			{
				cur = cur->right;
			}
			else
			{
				return true;
			}
		}
		return false;
	}
	void erase(const T& val)
	{
		node* cur = _root;
		node* parent = _root;
		
		while (cur)
		{
			if (cur->val > val)
			{
				parent = cur;
				cur = cur->left;
			}
			else if (cur ->val < val)
			{
				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 if (parent->right == cur)
					{
						parent->right = cur->right;
					}
					delete cur;
				}
				else if(cur->right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->left;
					}
					else if (parent->left == cur)
					{
						parent->left = cur->left;
					}
					else if (parent->right == cur)
					{
						parent->right = cur->left;
					}
					delete cur;
				}
				else
				{
					node* tmp = cur->right;
					node* tp = cur;
					while (tmp->left)
					{
						tp = tmp;
						tmp = tmp->left;
					}
					swap(cur->val, tmp->val);
					
					// 交换完,就相当是删除tmp,tmp的特点是左子树为空
					// 也相当于是删除没有左子树的节点

					if (tp->left == tmp)
						tp->left = tmp->right;
					else
						tp->right = tmp->right;

					delete tmp;

				}
			}
		}
	}
private:
	void _inorder(node* root)
	{
		if (root == nullptr) return;

		_inorder(root->left);
		cout << root->val << " ";
		_inorder(root->right);
	}
private:
	node* _root;

};

三、K-V模型

什么叫K-V模型?

其全称是key-value模型,是一种映射关系。一个key(关键字)对应一个value(值)。

比如:英语和汉语就是一种kv模型。stl库中的map也是一种kv模型,不过底层不是用二叉搜索树实现的。

代码

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;

template<class K, class V>
struct BSTN
{
	typedef pair<K, V> PKV;
	BSTN(const PKV& e)
		:left(nullptr)
		,right(nullptr)
		,val(e)
	{}
	BSTN<K, V>* left;
	BSTN<K, V>* right;
	PKV val;
};

template<class K, class V>
class BST
{
	typedef pair<K, V> PKV;
	typedef BSTN<K, V> node;
public:
	BST()
		:_root(nullptr)
	{}
	void insert(const PKV& val)
	{
		if (_root == nullptr)
		{
			node* tmp = new node(val);
			_root = tmp;
			return;
		}
		node* parent = _root;
		node* cur = _root;
		while (cur)
		{
			if (cur->val.first > val.first)
			{
				parent = cur;
				cur = cur->left;
			}
			else
			{
				parent = cur;
				cur = cur->right;
			}
		}
		cur = new node(val);
		if (parent->val.first > val.first)
		{
			parent->left = cur;
		}
		else
		{
			parent->right = cur;
		}
	}
	void inorder()
	{
		_inorder(_root);
	}
	bool find(const K& val)
	{
		node* cur = _root;
		while (cur)
		{
			if (cur->val > val)
			{
				cur = cur->left;
			}
			else if (cur->val < val)
			{
				cur = cur->right;
			}
			else
			{
				return true;
			}
		}
		return false;
	}
	void erase(const PKV& val)
	{
		node* cur = _root;
		node* parent = _root;

		while (cur)
		{
			if (cur->val.first > val.first)
			{
				parent = cur;
				cur = cur->left;
			}
			else if (cur ->val.first < val.first)
			{
				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 if (parent->right == cur)
					{
						parent->right = cur->right;
					}
					delete cur;
				}
				else if(cur->right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->left;
					}
					else if (parent->left == cur)
					{
						parent->left = cur->left;
					}
					else if (parent->right == cur)
					{
						parent->right = cur->left;
					}
					delete cur;
				}
				else
				{
					node* tmp = cur->right;
					node* tp = cur;
					while (tmp->left)
					{
						tp = tmp;
						tmp = tmp->left;
					}
					swap(cur->val, tmp->val);

					// 交换完,就相当是删除tmp,tmp的特点是左子树为空
					// 也相当于是删除没有左子树的节点

					if (tp->left == tmp)
						tp->left = tmp->right;
					else
						tp->right = tmp->right;

					delete tmp;

				}
			}
		}
	}
private:
	void _inorder(node* root)
	{
		if (root == nullptr) return;

		_inorder(root->left);
		cout << root->val.first << " " << root->val.second << endl;
		_inorder(root->right);
	}
private:
	node* _root;

};
相关推荐
小字节,大梦想42 分钟前
【C++】二叉搜索树
数据结构·c++
吾名招财43 分钟前
yolov5-7.0模型DNN加载函数及参数详解(重要)
c++·人工智能·yolo·dnn
我是哈哈hh1 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
憧憬成为原神糕手1 小时前
c++_ 多态
开发语言·c++
郭二哈1 小时前
C++——模板进阶、继承
java·服务器·c++
挥剑决浮云 -1 小时前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记
丶Darling.2 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树
labuladuo5202 小时前
Codeforces Round 977 (Div. 2) C2 Adjust The Presentation (Hard Version)(思维,set)
数据结构·c++·算法
小柯J桑_2 小时前
C++:STL简介
c++·stl
咖啡里的茶i3 小时前
C++之继承
c++