二查排序树

二叉排序树(Binary Sort Tree),又称为二查搜索树。它要么是一颗空树,要么是符合性质的二叉树

  • 若它的左子树不为空,那么左子树上的所有结点的值均小于它的根结点的值
  • 若它的右子树不为空,那么右子树上的所有结点的值均大于它的根结点的值
  • 它的左右子树也分别为二叉排序树

以上性质就造成了左结点<根结点<右结点,那么可以想象一下,如果对二叉排序树进行中序遍历,很明显,我们得到的是一个递增的序列。我们可以根据这个,来判断自己建立的二叉排序树的正确性。需要说明的是,二叉排序树虽然带排序俩字,但却不是为了排序,而是为了提高查找和插入删除的效率。

接下来,我们看一下,二叉排序树的查找是如何实现的。首先给出二叉树的结点结构体

//二叉树结点结构定义
typedef struct BSTNode
{
	int m_data;
	BSTNode *Lchild,*Rchild;
}BSTNode,*BiTree;

二叉排序树查找代码如下

//在二查搜索树中查找特定的值,返回值在树中的地址	
//递归查找树pRoot中是否存在value
//指针pfather指向pRoot的双亲,当pRoot是开始的跟结点时,值为NULL
//指针pValue,指向找到value的结点,找不到则指向最后一个结点
bool SearchBST(BiTree pRoot,int value,BiTree pfather,BiTree *pValue)
{
	if (!pRoot)                //当最后发现value不存在时,pfther指向最后一个结点
	{
		*pValue = pfather;
		return false;
	}
	else if (value == pRoot->m_data)    //等于根结点,返回true
	{
		*pValue = pRoot;
		return true;
	}
	else if (value < pRoot->m_data)           //比根结点小,递归左子树查询
	{
		SearchBST(pRoot->Lchild,value,pRoot,pValue);
	}
	else                                                    
		SearchBST(pRoot->Rchild,value,pRoot,pValue); //递归右子树查询
}
以上代码很好理解,接下我们看一下如何对二叉排序树进行插入操作。

//向二叉排序树中插入一个元素value
//*pRoot代表一颗二叉排序树
bool insertBST(BiTree * pRoot, int value)
{
	BiTree p = NULL;                 //用于接收返回的查找的结点地址或路径中最后一个结点地址
	if (!SearchBST(*pRoot,value,NULL,&p))   //二叉排序树中不能有重复的值
	{
		BiTree s = new BSTNode();
		s->m_data = value;
		s->Lchild = NULL;
		s->Rchild = NULL;
		if (NULL == *pRoot)       //如果传过来的是一颗空树
		{
			*pRoot = s;
		}
		else if (value < p->m_data)  //比最后一个结点小,放左边
		{
			p->Lchild = s;
		}
		else
			p->Rchild = s;           //否则放右边
		return true;
	}
	else
	{
		cout<<"invalid value"<<endl;
		return false;
	}
}
插入有了,那么创建一颗二叉排序树的可想而知了

//创建二叉排序树
//state用于判断上一次插入是否成功,不成功返回
bool creatBinarySortTree(BiTree *pRoot,int *array, int size)
{
	bool state = true;
	for (int i = 0;(i < size)&&state; i++)
	{
		state = insertBST(pRoot, array[i]);
	}
	return state;
}
//销毁二查搜索树
void DestoryBST(BiTree pRoot)
{
	if(NULL != pRoot)
	{
		DestoryBST(pRoot->Lchild);  //释放左子树
		DestoryBST(pRoot->Rchild);  //释放右子树
		delete pRoot;
	}
}
好了,至此我们创建了一棵二叉排序树,可以对它进行查找,插入操作了,那么问题来了,我要是想对它进行删除怎么办?对于二叉排序树可是“请神容易送神难”。想想删除可那么简单,因为不能因为你删除了一个结点,这棵树就不是二叉排序树了吧?所以删除时,要考虑多种情况。
  • 删除的是叶子结点,可以想象,删除叶子结点不会对其他结点照成任何影响,此种情况可以直接删除。
  • 删除的结点仅有左子树或者右子树,这种情况也相对容易,我把那个结点删除了,把它的左子树或者右子树整体移动到它的位置就可以了。
  • 左右子树都存在,那么找要删除结点的前驱或者后继去替换它,然后把它的前驱或者后继删掉。

接下来看看代码怎么怎么写

<pre name="code" class="cpp">bool deleteBST(BiTree *pRoot,int key)
{
	if (!*pRoot)         //删除的结点不存在
		return false;
	else
	{
		if (key == (*pRoot)->m_data)        //找到值等于key的结点
			return	Delete(pRoot);
		else if (key < (*pRoot)->m_data)
		{
			return deleteBST(&(*pRoot)->Lchild,key);
		}
		else
			return deleteBST(&(*pRoot)->Rchild,key);
	}
}
bool Delete(BiTree * pRoot)
{
	BiTree q = NULL ,s = NULL;
	if ((*pRoot)->Lchild == NULL)   //左子树为空,重接右子树
	{
		q = *pRoot;
		(*pRoot) = (*pRoot)->Rchild;
		free(q);
	}
	else if ((*pRoot)->Rchild == NULL) //右子树为空,重接左子树
	{
		q =*pRoot;
		*pRoot = (*pRoot)->Lchild;
		free(q);
	}
	else
	{
		q = *pRoot;           //q指向待删除的结点
		s =(*pRoot)->Lchild;   //
		while (s->Rchild)        //前驱没有右子树
		{
			q = s;
			s = s->Rchild;
		}
		(*pRoot)->m_data = s->m_data;  //s指向被删除结点的前驱
		if (q != *pRoot)
		{
			q->Rchild = s->Lchild;   //前驱的左孩子做前驱父节点的右孩子
		}
		else
		{
			q->Lchild = s->Lchild; //重接q的左子树
		}
		free(s);
	}
	return true;
}

 

二叉排序树的查找,走的就是根节点到要查找的结点路径,其比较次数等于给定值的结点在二叉树的深度,极端情况下,最少为1,即根节点就是要找的结点,最多不会超过树的深度,也就是说,查找的时间很大层度上取决于树的形状,但是二叉排序树的形状又是不确定的,那么问题有来了,由于形状的不同,查找的时间差异很大,怎么样才能保证树的深度呢,嘿嘿,往下就涉及到了平衡二叉树。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值