加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 服务器 > 安全 > 正文

【数据结构】二叉查找树

发布时间:2021-05-22 19:33:20 所属栏目:安全 来源:网络整理
导读:副标题#e# 1、概念: 二叉查找树,也称排序二叉树,是指一棵空树或者具备下列性质的二叉树(每个节点都不能有多于两个儿子的树): 1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 2. 若任意节点的右子树不空,则右子树上所有节点

如果删除节点6,也就是根节点,先用其右子树的最小数据节点8代替该节点的数据,然后递归的删除节点8,这样删除节点8就和删除只有右儿子的数据节点操作(第4点)是一样的了。

为什么是用右子树的最小节点来替代呢?因为根据二叉查找树的特性,某节点的右子树的最小数据节点大于该节点的所有左子树节点,小于该节点的右子树节点当中除了最小节点的所有节点,这样用这个右子树最小数据节点代替该节点,那么操作之后的还是二叉查找树。


3)删除节点只有左儿子:

1. 该左儿子是叶子节点。删除节点4,由于节点(2)的右子树的所有节点键值均大于该节点键值,所以删除节点4后,直接用该节点的左儿子3取代节点4,这里的取代是将节点4的键值替换为3,这样该树中就有两个键值为3的节点,然后删除其左儿子节点3。过程如下图所示

/*
*              6                             6                       6
*             /                            /                      /  
*            2   8                         3   8                   3   8
*           /            -->            /            -->      /    
*          1   4   10                    1   3   10              1   3   10
*             /                             /
*            3                             3
*/

2. 该左儿子不是叶子节点,考虑下面这种情况:删除节点6,那么就需要先查找该节点6左子树的最大数据节点替代该节点,然后递归的删除该左子树的最大数据节点,过程如下所示,至于为什么是左子树的最大数据节点,原因和上面分析的一样。

/*
*             6                             4                       4                 4
*            /                             /                       /                 /
*           2                             2                       2                 2
*          /             -->            /             -->      /      -->       / 
*         1   4                         1   4                   1   3             1   3
*            /                             /                       /
*           3                             3                       3
*/

4)删除节点只有右儿子:

1. 该右儿子是叶子节点,删除节点8,这个和删除只有左儿子的节点操作一样,过程如下所示

/*
*              6                             6                       6
*             /                            /                      /  
*            2   8                         3   10                  3   10
*           /            -->            /            -->      /    
*          1   4   10                    1   4   10              1   4   
*             /                             /
*            3                             3
*/
2. 该右儿子不是叶子节点 :删除节点2,先找到该节点右子树的最小数据节点并用最小节点数据代替该节点,然后递归的删除最小节点,其实此时的最小节点就是右子树的左叶子节点,可以直接删除。过程如下所示

/*
*              6                             6                       6                 
*             /                             /                       /                 
*            2                             3                       3                  
*                         -->                          -->             
*              4                             4                       4            
*             /                             /                        
*            3                             3                        
*/

从上面分析可以看出,删除操作是用树中的某个数据代替删除节点键值,实际上删除的都是叶子节点。有了上面的分析,程序就水到渠成了,如下所示

/*
*删除操作需要修改节点指针,故采用二级指针传递
*删除操作就是不断的转移目标节点,直到目标节点为叶子节点了,就删除
*/
bool deleteNode(BinaryTree **pBinaryNode,int key)
{
	BinaryTree *pTempNode = NULL;

	if ((NULL == pBinaryNode) || (NULL == *pBinaryNode))  //树为空或未找到目标节点
		return false;

	/*查找目标节点*/
	else if (key < (*pBinaryNode)->value)
		return deleteNode(&(*pBinaryNode)->left_child,key);
	else if (key >(*pBinaryNode)->value)
		return deleteNode(&(*pBinaryNode)->right_child,key);

	/*已找到目标节点pBinaryNode*/
	/*目标节点有两个儿子*/
	else if ((*pBinaryNode)->left_child && (*pBinaryNode)->right_child)
	{
		pTempNode = findMin((*pBinaryNode)->right_child);  //找到右子树的最小节点
		(*pBinaryNode)->value = pTempNode->value;
		return deleteNode(&(*pBinaryNode)->right_child,(*pBinaryNode)->value);  //递归地删除该节点
	}/*此处参数以及后面的递归删除参数均不能用pDelNode替代,必须用现在这个,否则打印时出现乱码*/
	else
	{    /*目标节点只有左儿子*/
		if ((*pBinaryNode)->left_child && (NULL == (*pBinaryNode)->right_child))
		{
			pTempNode = findMax((*pBinaryNode)->left_child);  //找到左子树的最大节点
			(*pBinaryNode)->value = pTempNode->value;
			return deleteNode(&(*pBinaryNode)->left_child,(*pBinaryNode)->value);
		}
		/*目标节点只有右儿子*/
		else if ((*pBinaryNode)->right_child && (NULL == (*pBinaryNode)->left_child))
		{
			pTempNode = findMin((*pBinaryNode)->right_child); //找到右子树的最小节点
			(*pBinaryNode)->value = pTempNode->value;
			return deleteNode(&(*pBinaryNode)->right_child,(*pBinaryNode)->value);
		}
	/*目标节点没有儿子,含叶子节点和没有儿子的根节点情况*/
	/*实际上几乎所有删除节点操作都会执行下面这步,也就是递归地删除节点最终会递归到删除某叶子节点*/
		else
		{
			free(*pBinaryNode);       //已经递归到叶子节点
			(*pBinaryNode) = NULL;   
		}
	}

	return true;
}

上述情况均逐一测试通过,测试环境:Visual Studio 2013

8、树的遍历

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读