二叉排序树

本文详细介绍了二叉排序树的基本概念及其查找、插入和删除操作的实现方法,并分析了二叉排序树的查找性能。

动态查找表是在查找过程中动态生成的,也就是对于给定值key,如果查找表中存在关键字等于key的元素,则查找成功;否则,在查找表中插入关键字等于key的元素。动态查找表有不同的实现方法,接下来介绍三种实现方法。

第一种,也就是今天要写的二叉排序树。

1. 二叉排序树的定义

二叉排序树是一种特别的二叉树,它的具体定义如下:

(1)若它的左子树不空,则左子树上所有结点的关键字值均小于它的根节点的关键字值。

(2)若它的右子树不空,则右子树上所有结点的关键字值均大于它的根节点的关键字值。

(3)它的左右子树仍为二叉排序树。

2.二叉排序树的基本操作之查找(Find)

二叉排序树的查找操作比较简单,我们可以根据它的定义来实现。

当二叉排序树不为空时,将给定值与根节点进行比较,若相等,则视为找到;若不相等,则比较给定值与根节点的值的大小,若小于,则前进至左子树;若大于,则前进至右子树。在下一结点中重复此过程,直到查找成功,或向前行进至一空子树时为止。

bool Find(const K& key)
	{
		PNode _PRoot = GetRoot();
		assert(_PRoot);
		PNode Pcur = _PRoot;
		while (Pcur)
		{
			if (key == Pcur->_key)
				return true;
			else if (key < Pcur->_key)
				Pcur = Pcur->_PLeft;
			else
				Pcur = Pcur->_PRight;
		}
		return false;
	}

3.二叉排序树基本操作之插入(Insert)

在二叉排序树中插入一个结点,形成的二叉树仍然是二叉排序树。

要插入一个新的结点,首先需要查找二叉排序树。若查找失败,则插入新结点,在此过程中,我们需要标记双亲结点,根据插入元素的值决定新节点是左子树还是右子树。

bool _InsertNode(const K& key, const V& value)
	{
		if (_PRoot == NULL)
		{
			_PRoot = new Node(key, value);
		}
		PNode Pcur = _PRoot;
		PNode pParent = NULL;
		while (Pcur)
		{
			if (key == Pcur->_key)
				return false;
			else if (key < Pcur->_key)
			{
				pParent = Pcur;
				Pcur = Pcur->_PLeft;
			}
				
			else
			{
				pParent = Pcur;
				Pcur = Pcur->_PRight;
			}
		}
		if (pParent)
		{
			PNode newNode = new Node(key, value);
			if (pParent->_key > key)
				pParent->_PLeft = newNode;
			else
				pParent->_PRight = newNode;

		}
		return true;
	}

4.二叉排序树基本操作之删除(Delete)

在进行删除操作时,需要先查找要删除的关键字值是否在二叉排序树中。假设二叉排序树不空,并且要删除的关键字在二叉排序树中,则对于要删除的结点分为4种情况。假设要删除的结点为Del。

(1)Del 结点无左子树和右子树,此时直接删除,并置为NULL即可。

(2)Del结点只有左孩子

(3)Del结点只有右子树

(4)Del结点左右子树都存在

bool _Delete(const K& key)
	{
		if (_PRoot == NULL)
			return false;
		PNode Pcur = _PRoot;
		PNode pParent = NULL;
		while (Pcur)
		{
			if (Pcur->_key == key)
				break;
			else if (Pcur->_key < key)
			{
				pParent = Pcur;
				Pcur = Pcur->_PRight;
			}
			else
			{
				pParent = Pcur;
				Pcur = Pcur->_PLeft;
			}
		}
		if (Pcur)
		{
			//只有右子树
			if (Pcur->_PLeft == NULL)
			{
				if (Pcur == _PRoot)
				{
					_PRoot = Pcur->_PRight;
					delete Pcur;
				}
				else
				{
					if (Pcur == pParent->_PLeft)
						pParent->_PLeft = Pcur->_PRight;
					else
						pParent->_PRight = Pcur->_PRight;
				}
			}
			//只有左子树
			else if(Pcur->_PRight == NULL)
			{
				if (Pcur == _PRoot)
				{
					_PRoot = Pcur->_PLeft;
					delete Pcur;
				}
				else
				{
					if (Pcur == pParent->_PLeft)
						pParent->_PLeft = Pcur->_PLeft;
					else
						pParent->_PRight = Pcur->_PLeft;
				}
			}
			else if (Pcur->_PLeft &&Pcur->_PRight)
			{
				//找中序遍历的第一个结点(右子树的最左侧的结点)
				PNode firstOfOrder = Pcur->_PRight;
				PNode ppParent = Pcur;//first的双亲结点
				while (firstOfOrder->_PLeft)
				{
					ppParent = firstOfOrder;
					firstOfOrder = firstOfOrder->_PLeft;
				}

				//删除待删除的结点
				Pcur->_key = firstOfOrder->_key;
				Pcur->_value = firstOfOrder->_value;

				//连接替换结点的指针域
				if (firstOfOrder == ppParent->_PLeft)
				{
					ppParent->_PLeft = firstOfOrder->_PRight;

				}
				else
				{
					ppParent->_PRight = firstOfOrder->_PRight;
				}
				delete firstOfOrder;
				firstOfOrder = NULL;
			}
			return true;
		}
		return false;
	}

6. 二叉排序树的查找性能

(1)最坏情况:数据序列为有序排列的,此时二叉排序树为一棵深度为 n 的单支树。此时平均查找长度 ASL=(n+1)/2 ;

(2)最优情况:数据序列无序,与折半查找判定树相似的二叉排序树,此时平均查找长度 ASL=logN;

综上,在一般情况下,其平均查找长度ASL =LogN;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值