二叉搜索树的模拟实现与总结

本文介绍了二叉搜索树的概念、性质,并详细解释了如何验证一个树是否为二叉搜索树。讨论了其性能分析,指出插入顺序影响树的结构,举例展示了最优(完全二叉树)和最差(右单支)情况下的平均查找长度。最后提到了二叉搜索树的模拟实现。
摘要由CSDN通过智能技术生成

什么是二叉搜索树?

二叉搜索树又称二叉排序树。(⚠️:空树也是一颗二叉搜索树

二叉搜索树的性质

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

如何验证一个树是不是二叉搜索树?

  1. 搜索二叉搜索树的中序遍历一定是一个有序的数据集合。
  2. 二叉搜索树的最左边节点一定是最小的节点。
  3. 二叉搜索树的最右边节点一定是最大的节点。

二叉搜索树的性能分析

二叉搜索树的插入和删除都必须先查找,因此,查找效率便代表了二叉搜索树中各个操作的性能。

假设有一个n个节点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是节点在二叉搜索树的深度的函数,即节点越深,则比较次数越多。

但是对于一个数据集合,插入顺序不同,可能得到不同结构的二叉搜索树。

例:有数据集合  int a[7] = {3,4,5,6,7,8,9};

1、右单支二叉搜索树{3,4,5,6,7,8,9}

2、完全二叉树{6,4,3,5,8,7,9}

性能分析:

最优情况下,二叉搜索树为完全二叉树,平均比较次数为:lgN(注:这里是log以二为底的N)

最差情况下,二叉搜索树为右单支,平均比较次数为:N/2;

二叉搜索树的模拟实现

//二叉搜索树(binary search tree)

#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)
	{}

	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;
		}

		// 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;

		// 1、找待删除节点的位置
		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;

		// 2、删除该节点
		Node* pDelNode = pCur;
		// pCur可能是叶子节点 || 只有右孩子
		if (nullptr == pCur->_pLeft)
		{
			// 所有的叶子节点和只有右孩子的节点
			if (nullptr == pParent)
			{
				// pCur是根节点
				_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
		{
			// 左右孩子均存在
			// 在pCur的右子树中找一个替代节点-->一定是右子树中最小的节点(最左侧节点)
			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;
	}

	// 验证:
        //1、中序遍历后的数列一定有序
        //这里只给用户一个接口,为了方便用户使用
	void InOrder()
	{
		_InOrder(_pRoot);
	}
        
        //最左边的节点一定是最小的
	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;
	}

private:
        //这里把中序遍历的方法给成私有的,是为了让用户不用传参调用函数,方便用户使用
	void _InOrder(Node* pRoot)
	{
		if (pRoot)
		{
			_InOrder(pRoot->_pLeft);
			cout << pRoot->_data << " ";
			_InOrder(pRoot->_pRight);
		}
	}
private:
	Node* _pRoot;
};


void TestBSTree()
{
	BSTree<int> t;

	int a[] = { 5, 3, 4, 1, 7, 8, 2, 6, 0, 9 };
	for (auto e : a)
		t.Insert(e);

	t.InOrder();
	cout << endl;
	cout << t.LeftMost()->_data << endl;
	cout << t.RightMost()->_data << endl;

	t.Delete(6);
	t.InOrder();
	cout << endl;

	t.Delete(8);
	t.InOrder();
	cout << endl;

	t.Delete(5);
	t.InOrder();
	cout << endl;
}
int main()
{
   TestBSTree();
   return 0;
]

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值