二叉搜索树

map/multimap/set/multiset的底层都是按照二叉搜索树来实现的
二叉搜索树
即二叉排序树,为空树或者满足下列性质:

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

二叉搜索树的查找
二叉搜索树_第1张图片
二叉搜索树的插入
二叉搜索树_第2张图片
二叉搜索树的删除

  • 先查找元素是否在二叉搜索树种,不存在返回,否则:
    1.要删除的节点无孩子节点
    2.要删除的节点只有左孩子节点(删除该节点且使删除节点的双亲节点指向被删除节点的左孩子节点)
    3.要删除的节点只有右孩子节点(删除该节点且使被删除节点的双亲节点指向被删除节点的右孩子节点)
    4.要删除的节点有左,右孩子节点(在它的右子树中寻找中序下的第一个节点(关键码最小), 用它的值填补到被删除节点中)从右子树找最小值,从左子树找最大值
#pragma once
#include 

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;
	typedef Node* PNode;
public:
	BSTree()
		:_proot(nullptr)
	{}

	//根据二叉树的查找性质: 找到值为data的节点在二叉树中的位置
	PNode Find(const T& data);
	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;

	}
	bool Erase(const T& data)
	{
		//如果树为空删除失败
		if (_proot == nullptr)
		{
			return false;
		}
		 
		//查找data在树中所在位置
		PNode pcur = _proot;
		PNode pParent = nullptr;
		while (pcur)
		{
			if (data == pcur->_data);
			{
				break;
			}
			else if (data > pcur->_data)
			{
				pParent = pcur;
				pcur = pcur->_pright;
			}
			else
			{
				pParent = pcur;
				pcur = pcur->_pleft;
			}

			//data不在树中,删除失败
			if (pcur == nullptr)
			{
				return false;
			}

			//只有左孩子
			if (nullptr == pcur->_pright)
			{
				if (pParent->_pleft == pcur)
				{
					pParent->_pleft == pcur->pleft;
				}
				else
				{
					pParent->_pright == pcur->pleft;
				}
			}
			//只有右孩子
			if (nullptr == pcur->_pleft)
			{
				if (pParent->_pleft == pcur)
				{
					pParent->_pleft == pcur->pright;
				}
				else
				{
					pParent->_pright == pcur->pright;
				}
			}
			else
			{
				Node* rpParent = pcur;
				Node* replace = pcur->_pright;
				while (replace->_pleft)
				{
					rpParent = replace;
					replace = replace->_pleft;
				}
				pcur->_data = replace->_data;
				pcur = replace;
				if (rpParent->_pleft == replace)
				{
					rpParent->_pleft = replace->_pright;
				}
			}
			delete pcur;
			return true;
		}
		return false;
	}

	void InOrder()
	{
		_InOrder(_proot);
		cout << endl;
	}

	void _InOrder(Node* _proot)
	{
		if (_proot == nullptr)
			return;

		if (_proot)
		{
			_InOrder(_proot->_pleft);
			cout << _proot->_data << " ";
			_InOrder(_proot->_pright);
		}
	}

private:
	PNode _proot;
};

二叉树的性能
插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同的结构的二叉树
最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2

你可能感兴趣的:(二叉搜索树)