二叉搜索树

二叉搜索树

1. 二叉搜索树的概念

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

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 并且它的左右子树也分别为二叉搜索树

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

2.二叉搜索树的创建,插入,查找,删除
2.1 创建
   二叉搜索树的创建,等同于二叉树的创建过程,区别是,在插入的过程需要进行数值
大小比较,把节点放在它最合适的地方,保证插入后,二叉搜索树的中序遍历结果是有序
的即可。
  如果是空树,就将插入的节点作为根节点。如果不是空树,就和根节点进行比较,比根
节点中的值小,就到根的左孩子中寻找,比根节点值大的就去根的右孩子中寻找。如果在
查找过程中,遇到了相同的元素,就可以直接返回(本题中只考虑插入不同的元素),当
遇到空节点的时候说明位置找到了,即可插入。
创建和插入的代码:
//插入数据,已有的数据不会重复插入
	bool Insert(const T& data) 
	{
		//如果是空树,将要插入的将数据作为根节点
		if (_pRoot == nullptr)
		{
			_pRoot = new Node(data);
			return true;
		}

		//如果不是空树,查找要插入的位置
		PNode pCur = _pRoot;
		PNode pParent = nullptr;
		while (pCur)
		{
			pParent = pCur;
			if (data < pCur->_data)
				pCur = pCur->_pLeft;
			else if (data > pCur->_data)
				pCur = pCur->_pRight;
			else
				return false;
		}
		
		//走到这里,说明二叉树中没有要插入的重复数据,就可以插入节点
		pCur = new Node(data);
		if (data < pParent->_data)
			pParent->_pLeft = pCur;
		else
			pParent->_pRight = pCur;
		return true;
	}
2.2查找
     包括查找某个特定值的节点,查找最右边的节点,查找最左边的节点。
     方法:先与根节点内容比较,在根据大小关系在子树中进行查找。最左边的节点
  也就是值最小的节点。最右边的节点是值最大的节点。

代码如下:

	//获取最左边的节点
	PNode MostLeft()
	{
		if (_pRoot == nullptr)
			return nullptr;
		PNode pCur = _pRoot;
		while (pCur->_pLeft)
		{
			pCur = pCur->_pLeft;
		}
		return pCur;
	}

	//获取最右边的节点
	PNode MostRight()
	{
		if(_pRoot == nullptr)
			return nullptr;
		PNode pCur = _pRoot;
		while (pCur->_pRight)
		{
			pCur = pCur->_pRight;
		}
		return pCur;
	}

//查找二叉搜索树中的节点
PNode Find(const T& data)
	{
		PNode pCur = _pRoot;
		while (pCur)
		{
			if (pCur->_data == data)
				return pCur;
			else if (data > pCur->_data)
				pCur = pCur->_pRight;
			else
				pCur = pCur->_pLeft;
		}
		return nullptr;
	}

2.3删除二叉搜索树的节点
     删除节点是二叉搜索树相关内容中较为复杂的内容,以图示意。


在这里插入图片描述
代码如下:

//删除节点
	bool Erase(const T& data)
	{
		//找待删除的节点
		PNode pCur = _pRoot;
		PNode pParent = nullptr;
		PNode AlterNode = nullptr;
		while (pCur)
		{
			if (data < pCur->_data)
			{
				pParent = pCur;
				pCur = pCur->_pLeft;
			}
			else if (data > pCur->_data)
			{
				pParent = pCur;
				pCur = pCur->_pRight;
			}
			//找到节点
			else
			{
				if (pCur->_pLeft == nullptr) //要删除的节点只有右孩子 或者 是叶子结点都能进入
				{
					if (pParent->_pRight == pCur) //要删除的节点是双亲节点的右孩子
					{
						pParent->_pRight = pCur->_pRight;
						delete pCur;
					}
					else  //要删除的节点(该节点只有右孩子的同时)是双亲节点的左孩子
					{
						pParent->_pLeft = pCur->_pRight;
						delete pCur;
					}
					return true;
				}
				else if (pCur->_pRight == nullptr)
				{
					//要删除的节点 只有左孩子
					pParent->_pRight = pCur->_pLeft;
					delete pCur;
					return true;
				}
				else
				{
					//要删除的节点是  左右孩子都有
					//先找到右子数中的最小的节点
					AlterNode = pCur;
					pParent = nullptr;
                
                	AlterNode = pCur->_pRight;
					while (AlterNode->_pLeft)
					{
						pParent = AlterNode;
						AlterNode = AlterNode->_pLeft;
					}
					pCur->_data = AlterNode->_data;
					pParent->_pLeft = AlterNode->_pLeft;
					delete AlterNode;
					return true;
				}
			}	
		}
		return false;
	}

——————————————————————————————————
二叉搜索树总体代码:

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

template <class T>
struct BSTNode
{
	BSTNode(const T& data)
		:_pLeft(nullptr)
		, _pRight(nullptr)
		, _data(data)
	    {}
	BSTNode<T>* _pLeft;
	BSTNode<T>* _pRight;
	T _data;
};

template<class T>
class BSTree
{
	typedef BSTNode<T> Node;
	typedef BSTNode<T>* PNode;
public:
	BSTree()
		:_pRoot(nullptr)
	{}

	//插入数据,已有的数据不会重复插入
	bool Insert(const T& data) 
	{
		//如果是空树,将要插入的将数据作为根节点
		if (_pRoot == nullptr)
		{
			_pRoot = new Node(data);
			return true;
		}

		//如果不是空树,查找要插入的位置
		PNode pCur = _pRoot;
		PNode pParent = nullptr;
		while (pCur)
		{
			pParent = pCur;
			if (data < pCur->_data)
				pCur = pCur->_pLeft;
			else if (data > pCur->_data)
				pCur = pCur->_pRight;
			else
				return false;
		}
		
		//走到这里,说明二叉树中没有要插入的重复数据,就可以插入节点
		pCur = new Node(data);
		if (data < pParent->_data)
			pParent->_pLeft = pCur;
		else
			pParent->_pRight = pCur;
		return true;
	}

	//获取最左边的节点
	PNode MostLeft()
	{
		if (_pRoot == nullptr)
			return nullptr;
		PNode pCur = _pRoot;
		while (pCur->_pLeft)
		{
			pCur = pCur->_pLeft;
		}
		return pCur;
	}

	//获取最右边的节点
	PNode MostRight()
	{
		if(_pRoot == nullptr)
			return nullptr;
		PNode pCur = _pRoot;
		while (pCur->_pRight)
		{
			pCur = pCur->_pRight;
		}
		return pCur;
	}

	//中序遍历
	void InOrder()
	{
		_InOrder(_pRoot);
	}

	//销毁二叉搜索树
	void Destroy(PNode& pRoot)
	{
		if (_pRoot == nullptr)
			return ;
		else
			Destroy(pRoot->_pLeft);
		    Destroy(pRoot->_pRight);
			delete pRoot;
			pRoot = nullptr;
	}

	//删除节点
	bool Erase(const T& data)
	{
		//找待删除的节点
		PNode pCur = _pRoot;
		PNode pParent = nullptr;
		PNode AlterNode = nullptr;
		while (pCur)
		{
			if (data < pCur->_data)
			{
				pParent = pCur;
				pCur = pCur->_pLeft;
			}
			else if (data > pCur->_data)
			{
				pParent = pCur;
				pCur = pCur->_pRight;
			}
			//找到节点
			else
			{
				if (pCur->_pLeft == nullptr) //要删除的节点只有右孩子 或者 是叶子结点都能进入
				{
					if (pParent->_pRight == pCur) //要删除的节点是双亲节点的右孩子
					{
						pParent->_pRight = pCur->_pRight;
						delete pCur;
					}
					else  //要删除的节点(该节点只有右孩子的同时)是双亲节点的左孩子
					{
						pParent->_pLeft = pCur->_pRight;
						delete pCur;
					}
					return true;
				}
				else if (pCur->_pRight == nullptr)
				{
					//要删除的节点 只有左孩子
					pParent->_pRight = pCur->_pLeft;
					delete pCur;
					return true;
				}
				else
				{
					//要删除的节点是  左右孩子都有
					//先找到右子数中的最小的节点
					AlterNode = pCur;
					pParent = nullptr;
                
                	AlterNode = pCur->_pRight;
					while (AlterNode->_pLeft)
					{
						pParent = AlterNode;
						AlterNode = AlterNode->_pLeft;
					}
					pCur->_data = AlterNode->_data;
					pParent->_pLeft = AlterNode->_pLeft;
					delete AlterNode;
					return true;
				}
			}	
		}
		return false;
	}


	PNode Find(const T& data)
	{
		PNode pCur = _pRoot;
		while (pCur)
		{
			if (pCur->_data == data)
				return pCur;
			else if (data > pCur->_data)
				pCur = pCur->_pRight;
			else
				pCur = pCur->_pLeft;
		}
		return nullptr;
	}

private:
	void _InOrder(PNode pRoot)
	{
		if (pRoot)
		{
			_InOrder(pRoot->_pLeft);
			cout << pRoot->_data<<" ";

			_InOrder(pRoot->_pRight);
		}
	}

private:
	PNode _pRoot;  
};

void TestBSTree()
{
	int array[] = { 5,2,3,7,6,4,9,1,8,0 };
	BSTree<int> t;
	for (auto e : array)
		t.Insert(e);
	t.InOrder();
	cout << endl;
	t.Erase(9);
	t.InOrder();
	cout << endl;

	t.Erase(3);
	t.InOrder();
	cout << endl;

	t.Erase(0);
	t.InOrder();
	cout << endl;

	t.Erase(5);
	t.InOrder();
	cout << endl;

	t.Erase(1);
	t.InOrder();
	cout << endl;
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值