高阶数据结构 | 二叉搜索树(Binary Search Tree)

Posted _BitterSweet

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高阶数据结构 | 二叉搜索树(Binary Search Tree)相关的知识,希望对你有一定的参考价值。

1.二叉搜索树的概念

二叉搜索树又叫二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树
  • 总结就是只要符合根节点大于一边,小于一边即可
    在这里插入图片描述

2.二叉搜索树的特性

  • 二叉搜索树的中序遍历一定是有序的
    在这里插入图片描述

3.二叉搜索树的简单实现

3.1二叉搜索树的查找

  • 从根节点出发,如果大于根节点,则查找右子树,小于根节点,则查找左子树,如果遍历完还没有找到,则返回空
    在这里插入图片描述
//查找
	Node* find(const T& val)
	{
		//从根节点开始查找
		Node* cur = _root;
		while (cur)
		{
			if (cur->_val == val)
				return cur;
			else if (cur->_val < val)
				cur = cur->_right;
			else
				cur = cur->_left;
		}
		//不存在返回空
		return nullptr;
	}

3.2二叉搜索树的插入

  • 插入分两种情况,第一种是如果为空树,就直接插入
    在这里插入图片描述

  • 第二种,如果不是空树,则需要先搜索,再插入,并且判断数据是否存在
    在这里插入图片描述

//插入:1.空树(直接插入) 2.非空树(搜索+插入)还要判断数据是否存在
	bool insert(const T& val)
	{
		//判断是否为空树
		if (_root == nullptr)
		{
			_root = new Node(val);
			return true;
		}

		//搜索插入的位置
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->_val == val)
				return false;
			else if (cur->_val < val)
				cur = cur->_left;
			else
				cur = cur->_right;
		}
		//确定新插入数据的左右位置
		cur = new Node(val);
		if (parent->_val < val)
			parent->_right = cur;
		else
			parent->_left = cur;
		return true;
	}

3.3二叉搜索树的删除

  • 首先需要查找元素是否在树中,如果不存在直接返回
  • 如果元素存在,则一共存在以下几种情况:
  • 第一种:叶子节点(删除1,4,9)
    在这里插入图片描述
  • 第二种:删除的节点只有一个子树(删除 7),让需要被删除的节点的父亲直接指向子树
    在这里插入图片描述
  • 第三种:待删除的节点左右子树均有
    在这里插入图片描述
//删除
	bool erase(const T& val)
	{
		//1.判断根节点
		if (_root == nullptr)
			return false;
		Node* cur = _root;
		Node* parent = nullptr;
		//查找
		while (cur)
		{
			if (cur->_val == val)
				break;
			else if (cur->_val < val)
			{
				parent = cur;//更新节点
				cur = cur->_right;
			}			
			else
			{
				parent = cur;
				cur = cur->_left;
			}			
		}
		//判断cur是否为空
		if (cur == nullptr)
			return false;
		//删除:叶子or非叶子?
		//1.叶子节点
		if (cur->_left == nullptr && cur->_right == nullptr)
		{
			//判断删除的是否为根节点
			if (cur == _root)
			{
				_root = nullptr;
			}
			else
			{
				if (parent->_left == cur)
					parent->_left == nullptr;
				else
					parent->_right == nullptr;			
			}
			delete cur;
		}
		//2.非叶子节点
		//左边为空,右边不为空
		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;
		}
		//左边不为空,右边为空
		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;
		}
		//左右都不为空
		else
		{
			//左右孩子都存在
			//1.找左子树最右节点
			Node* child = cur->_left;
			parent = cur;
			while (child->_right)
			{
				parent = child;
				child = child->_right;
			}

			//2.最右节点的值覆盖cur位置的值
			cur->_val = child->_val;

			//3.重新链接
			if (parent->_left == child)
				parent->_left = child->_left;
			else
				parent->_right = child->_left;
			
			//4.删除最右节点
			delete child;
		}
		return true;
	}

3.4实现的源代码整合

#include<iostream>
using namespace std;
template<class T>
struct Node
{
	T _val;
	Node* _left;
	Node* _right;

	Node(const T& val = T())
		:_val(val)
		,_left(nullptr)
		,_right(nullptr)
	{}
};

template<class T>
class BST
{
public:
	typedef Node<T> Node;
	BST()//构造
		:_root(nullptr)
	{}
	BST(const BST<T>& val)//拷贝构造---深拷贝
	{
		//结构也要拷过来,走到什么位置,就把对应的节点创建出来
		_root = copy(bst._root);
	}
	//递归拷贝节点
	Node* copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* cur = new(root->_val);
		cur->_left = copy(root->_left);
		cur->_right = copy(root->_right);
		return cur;
	}
	~BST()
	{
		if (_root)
			destroy(_root);
	}
	//销毁
	void destroy(Node* root)
	{
		if (root)
		{
			destroy(root->_left);
			destroy(root->_right);
			delete root;
			root = nullptr;
		}
	}

	//查找
	Node* find(const T& val)
	{
		//从根节点开始查找
		Node* cur = _root;
		while (cur)
		{
			if (cur->_val == val)
				return cur;
			else if (cur->_val < val)
				cur = cur->_right;
			else
				cur = cur->_left;
		}
		//不存在返回空
		return nullptr;
	}
	

	//插入:1.空树(直接插入) 2.非空树(搜索+插入)还要判断数据是否存在
	bool insert(const T& val)
	{
		//判断是否为空树
		if (_root == nullptr)
		{
			_root = new Node(val);
			return true;
		}

		//搜索插入的位置
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->_val == val)
				return false;
			else if (cur->_val < val)
				cur = cur->_left;
			else
				cur = cur->_right;
		}
		//确定新插入数据的左右位置
		cur = new Node(val);
		if (parent->_val < val)
			parent->_right = cur;
		else
			parent->_left = cur;
		return true;
	}
	//删除
	bool erase(const T& val)
	{
		//1.判断根节点
		if (_root == nullptr)
			return false;
		Node* cur = _root;
		Node* parent = nullptr;
		//查找
		while (cur)
		{
			if (cur->_val == val)
				break;
			else if (cur->_val < val)
			{
				parent = cur;//更新节点
				cur = cur->_right;
			}			
			else
			{
				parent = cur;
				cur = cur->_left;
			}			
		}
		//判断cur是否为空
		if (cur == nullptr)
			return false;
		//删除:叶子or非叶子?
		//1.叶子节点
		if (cur->_left == nullptr && cur->_right == nullptr)
		{
			//判断删除的是否为根节点
			if (cur == _root)
			{
				_root = nullptr;
			}
			else
			{
				if (parent->_left == cur)
					parent->_left == nullptr;
				else
					parent->_right == nullptr;			
			}
			delete cur;
		}
		//2.非叶子节点
		//左边为空,右边不为空
		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;
		}
		//左边不为空,右边为空
		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;
		}
		//左右都不为空
		else
		{
			//左右孩子都存在
			//1.找左子树最右节点
			Node* child = cur->_left;
			parent = cur;
			while (child->_right)
			{
				parent = child;
				child = child->_right;
			}

			//2.最右节点的值覆盖cur位置的值
			cur->_val = child->_val;

			//3.重新链接
			if (parent->_left == child)
				parent->_left = child->_left;
			else
				parent->_right = child->_left;
			
			//4.删除最右节点
			delete child;
		}
		return true;
	}

	//中序遍历:是有序的
	void inorder()
	{
		_inorder(_root);
		cout << endl;
	}
	void _inorder(Node* root)
	{
		if (root)
		{
			_inorder(root->_left);
			cout << root->_val << " ";
			_inorder(root->_right);
		}
	}
private:
	Node* _root;
};

4.二叉搜索树两种模型的简单实现

4.1 K模型

  • 只有K作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值
  • 例子:给一个单词word,判断该单词是否正确
  • 以单词集合中的每个单词作为key,构建一棵二叉搜索树
  • 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误
template <class K>
struct Node
{
	K _key;
	Node* _left;
	Node* _right;

	Node(const K& key = K())
		:_key(key)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

template <class K>
class BST
{
public:
	typedef Node<K> Node;
    
    //构造函数 
	BST()
		:_root(nullptr)
	{}
	//拷贝构造 
	BST(const BST<K>& key)//拷贝构造---深拷贝
	{
		//结构也要拷过来,走到什么位置,就把对应的节点创建出来
		_root = copy(bst._root);
	}
	//递归拷贝 
	Node* copy(Node* root)
	{
		if (root == nullptr)
			return nullptr;
		Node* cur = new(root->_key);
		cur->_left = copy(root->_left);
		cur->_right = copy(root->_right);
		return cur;
	}
	//析构函数 
	~BST()
	{
		if (_root)
			destory(_root);
	}
	//销毁 
	void destory(Node* root)
	{
		if (root)
		{
			destory(root->_left);
			destory(root->_right);
			delete root;
			root = nullptr;
		}
	}
	//查找 
	Node* find(const K& key)
	{
		//从根节点开始查找
		Node* cur = _root;
		while (cur)
		{
			if (cur->_key == key)
				return cur;
			else if (cur->_key < key)
				cur = cur->_right;
			else
				cur = cur->_left;
		}
		return nullptr;
	}
    //插入 
	bool insert(const K& key)
	{
		//判断是否为空树
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}

		//搜索插入的位置
		Node* cur = _root;
		Node* parent = nullptr;
		while (cur)
		{
			parent = cur;
			if (cur->_key == key)
				return false;
			else if (cur->_key < key)
				cur = cur->_right;
			else
				cur = cur->_left;
		}

		cur = new Node(key);
		//确定新插入数据的左右位置
		if (parent->_key < key)
			parent->_right = cur;
		else
			parent->_left = cur;
		return true;
	}
    //删除 
	bool erase(const K以上是关于高阶数据结构 | 二叉搜索树(Binary Search Tree)的主要内容,如果未能解决你的问题,请参考以下文章

[LeetCode] 109. 有序链表转换二叉搜索树

数据结构高阶第十篇——二叉搜索树(AVL树+红黑树)

数据结构05红-黑树基础----二叉搜索树(Binary Search Tree)

数据结构高阶第十篇——二叉搜索树(AVL树+红黑树)

4. 平衡二叉搜索树 --- BBST(Balance Binary Search Tree)

数据结构之二分搜索树(Binary Search Tree)