树中两个结点的最低公共祖先

本文探讨了在不同类型的二叉树中寻找两个节点的最低公共祖先的有效算法。包括二叉搜索树的特殊性质利用及普通二叉树的两种情况讨论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:输入两个树结点,求它们的最低公共祖先

题目一:如果这个树是二叉搜索树,二叉搜索树是排序过的,位于左子树的结点都比父结点小,而位于右子树的结点都比父结点大,我们只需要从树的根结点开始和两个输入的结点比较,如果输入两个结点都比根结点小,那么最低的共同父结点一定在当前结点的左子树中,于是下一步遍历当前结点的这左子结点。如果当前结点的值比两个结点都小,那么最低共同父结点一定在当前结点的右子树中,于是下一步遍历当前结点的右子结点。这样在树中从上到下找到的第一个在两个输入结点的值之间的结点,就是最低的公共祖先。

题目二:如果这个树不是二叉搜索树,不是二叉树,只是普通的数。如果树的结点有指向父结点的指针,那么可以转换为求两个链表的第一个公共交点,就是他们的最低公共祖先。


题目三:普通的树,树中的结点没有指向父结点的指针。


我们首先得到一条从根结点到树中某一结点的路径,这就要求在遍历的时候,有一个辅助内存来保存路径.比如我们用前序遍历的方法来得到从根结点到H 的路径的过程是这样的:( 1 )遍历到A,把A 存放到路径中去,路径中只有一个结点A; ( 2 )遍历到B,把B 存到路径中去,此时路径为A->B; ( 3 )遍历到D,把D 存放到路径中去,此,时路径为A->B->D; ( 4 ) :遍历到F,把F 存放到路径中去,此时路径为A->B->D->F;( 5) F 已经没有子结点了,因此这条路径不可能到这结点H. 把F 从路径中删除,变成A->B->D; ( 6 )遍历G. 和结点F 一样,这条路径也不能到达H. 边历完G 之后,路径仍然是A->B->D; ( 7 )由于D 的所有子结点都遍历过了,不可能到这结点H,因此D 不在从A 到H 的路径中,把D 从路径中删除,变成A->B; ( 8 )遥历E,把E 加入到路径中,此时路径变成A->B->E, ( 9 )遍历H,已经到达目标给点, A->B->E 就是从根结点开始到达H 必须经过的路径。
  同样,我们也可以得到从根结点开始到达F 必须经过的路径是A->B功。接着,我们求出这两个路径的最后公共结点,也就是B. B这个结点也是F 和H 的最低公共祖先.
  为了得到从根结点开始到输入的两个结点的两条路径,需要追历两次树,每边历一次的时间复杂度是O(n).得到的两条路径的长度在最差情况时是0(时,通常情况丁两条路径的长度是O(logn).

思路三代码如下:

bool GetNodePath(TreeNode* pRoot,TreeNode* pNode,list<TreeNode*>&path)
{
	if(pRoot==pNode)
		return true;
	path.push_back(pRoot);
	
	bool found=false;
	
	vector<TreeNode*>::iterator i=pRoot->m_vChildren.begin();
	while(!found && i<pRoot->m_vChildren.end())
	{
		found=GetNodePath(*i,pNode,path);
		++i;
	}
	if(!found)
		path.pop_back();
	
	return found;
}

TreeNode* GetLastCommonNode(const list<TreeNode*> path1,const list<TreeNode*> path2)
{
	list<TreeNode*>::const_iterator iterator1=path1.begin();
	list<TreeNode*>::const_iterator iterator2=path2.begin();
	
	TreeNode* pLast=NULL;
	
	while(iterator1!=path1.end() && iterator2 !=path2.end())
	{
		if(*iterator1==*iterator2)
			pLast=*iterator1;
		iterator1++;
		iterator2++;
	}
	return pLast;
	
}

TreeNode* GetLastCommonParent(TreeNode* pRoot,TreeNode* pNode1,TreeNode* pNode2)
{
	if(pRoot==NULL || pNode1==NULL || pNode2==NULL)
		return NULL;
	lsit<TreeNode*> path1;
	GetNodePath(pRoot,pNode1,path1);
	
	list<TreeNode*> path2;
	GetNodePath(pRoot,pNode2,path2);
	
	return GetLastCommonParent(path1,path2);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值