二叉搜索树的插入与删除

概念

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

  • 若它的左子树不为空,则左子树上的所有结点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上的所有结点的值都小于根节点的值
  • 它的左右子树也分别为二叉搜索树
    在这里插入图片描述
操作

1.查找
在这里插入图片描述
2.插入
a. 若树为空,直接插入数据
在这里插入图片描述
b.若树不为空,按照二叉搜索树的性质查找插入位置,插入新结点
在这里插入图片描述
3.删除
若要删除的结点不存在,则返回,若存在,则分为以下几种情况:
a.要删除的结点没有孩子
b.要删除的结点没有左孩子
c.要删除的结点没有右孩子
d.要删除的结点有左右孩子

因为删除结点的本质是:让待删除结点的双亲指向待删除结点的左孩子或着右孩子
在这里插入图片描述
所以,可将a,b或者a,c情况结合,删除过程中的实际操作为:

情况1:删除该结点,使该结点的双亲结点指向被删除结点的左孩子
在这里插入图片描述
情况2:删除该结点,使该结点的双亲结点指向被删除结点的右孩子
在这里插入图片描述
情况3:删除该结点,在它的右子树中找最小结点(在左子树中找最大结点),将最小结点的值填补到该结点,再删除最小结点。
在这里插入图片描述

代码
#include<iostream>
using namespace std;
template<class T>
struct BSTNode
{
	BSTNode(const T &data = T())
	: _pLeft(nullptr)
	, _pRight(nullptr)
	, _data(data)
	{}
	BSTNode<T> *_pLeft;
	BSTNode<T> *_pRight;
	T _data;
};


template<class T>
class BSTree
{
	typedef BSTNode<T> Node;
public:
	BSTree()
		: _pRoot(nullptr)
	{}
	//在二叉树搜索树中插入元素,成功返回true,失败返回false
	//这是比较简单的二叉搜索树,若元素已经存在,则不插入,返回false
	bool Insert(const T &data)
	{
		//空树
		if (nullptr == _pRoot)
		{
			_pRoot = new Node(data);
			return true;
		}
		//非空
		//1.按照二叉搜索树的查找特性,找到带插入节点在树中的位置
		Node *pCur = _pRoot;
		Node *pParent = nullptr;
		while (pCur)
		{
			pParent = pCur;
			if (data < pCur->_data)
				pCur = pCur->_pLeft;
			else if (data > pCur->_data)
				pCur = pCur->_pRight;
			else
				return false;//元素已经存在,不必插入,返回false
		}

		//2.插入新的结点
		pCur = new Node(data);
		if (data < pParent->_data)
			pParent->_pLeft = pCur;
		else
		    pParent->_pRight = pCur;
		return true;
	}
	bool Delete(const T& data)
	{
		if (nullptr == _pRoot)
			return false;
		//找到待删除结点的位置
		Node *pCur = _pRoot;
		Node *pParent = nullptr;
		while (pCur)
		{
			if (data == pCur->_data)
				break;
			else if (data < pCur->_data)
			{
				pParent = pCur;
				pCur = pCur->_pLeft;
			}
			else
				pParent = pCur;
			    pCur = pCur->_pRight;
		}
		if (nullptr == pCur)
			return false;

		//删除
		Node *pDelNode = pCur;
		if (nullptr == pCur->_pLeft)//叶子节点或者只有右孩子
		{
			if (nullptr == pParent)//若要删除的为根节点
				_pRoot = pCur->_pRight;
			else
			{
				if (pCur == pParent->_pLeft)
					pParent->_pLeft = pCur->_pRight;
				else
					pParent->_pRight = pCur->_pRight;
			}
		}
		else if (nullptr == pCur->_pRight)//只有左孩子
		{
			if (nullptr == pParent)//若要删除的结点为根节点
				_pRoot = pCur->_pLeft;
			else
			{
				if (pCur == pParent->_pLeft)
					pParent->_pLeft = pCur->_pLeft;
				else
					pParent->_pRight = pCur->_pLeft;
			}
		}
		else//左右孩子都存在
		{
			//可在左子树中找最大结点或者在右子树中找最小结点,本次采用在右子树中找最小结点
			Node *pDel = pCur->_pRight;
			pParent = pCur;
			while (pDel->_pLeft)
			{
				pParent = pDel;
				pDel = pDel->_pLeft;
			}
			pCur->_data = pDel->_data;
			//删除替代结点pDel
			if (pParent->_pLeft == pDel)
				pParent->_pLeft = pDel->_pRight;
			else
				pParent->_pRight = pDel->_pRight;
			pDelNode = pDel;
		}
		delete pDelNode;
		return true;
	}
	Node *Find(const T &data)
	{
		Node *pCur = _pRoot;
		while (pCur)
		{
			if (data == pCur->_data)
				return pCur;
			else if (data < pCur->_data)
				pCur = pCur->_pLeft;
			else
				pCur = pCur->_pRight;
		}
		return nullptr;
	}
	Node *LeftMost()
	{
		if (nullptr == _pRoot)
			return nullptr;
		Node *pCur = _pRoot;
		while (pCur->_pLeft)
		{
			pCur = pCur->_pLeft;
		}
		return pCur;
	}
	Node *RightMost()
	{
		if (nullptr == _pRoot)
			return nullptr;
		Node *pCur = _pRoot;
		while (pCur->_pRight)
		{
			pCur = pCur->_pRight;
		}
		return pCur;
	}
	void InOrder()//进行一次封装,减少用户传参
	{
		_InOrder(_pRoot);
	}
private:
	void _InOrder(Node *pRoot)//中序遍历
	{
		if (pRoot)
		{
			_InOrder(pRoot->_pLeft);
			cout << pRoot->_data << " ";
			_InOrder(pRoot->_pRight);
		}
	}
private:
	Node *_pRoot;
};

int main()
{
	BSTree<int> a;
	a.Insert(5);
	a.Insert(3);
	a.Insert(4);
	a.Insert(1);
	a.Insert(7);
	a.Insert(8);
	a.Insert(2);
	a.Insert(6);
	a.Insert(0);
	a.Insert(9);
	a.InOrder();
	cout << endl;
	a.Delete(8);
	a.InOrder();
	cout << a.Find(6) << endl;
	cout << a.LeftMost()->_data << " " << a.RightMost()->_data << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值