二叉树系列——两个节点的最低公共祖先

出处:https://segmentfault.com/a/1190000003509399


二叉搜索树:

Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that 
has both v and w as descendants (where we allow a node to be a descendant of itself).”

_______6______
/              \
___2__          ___8__
/      \        /      \
0      _4       7       9
/  \
3   5
For example, the lowest common ancestor (LCA) of nodes 2 and 8 is 6. 
Another example is LCA of nodes 2 and 4 is 2, 
since a node can be a descendant of itself according to the LCA definition.


思路:


对于二叉搜索树来说,公共祖先的值一定大于等于较小的节点,小于等于较大的节点。换言之,在遍历树的时候,如果当前结点大于两个节点,则结果在当前结点的左子树里,如果当前结点小于两个节点,则结果在当前节点的右子树里。


代码如下:

//二叉搜索树两个节点的最低公共祖先,参数为两个节点的值
BinaryTreeNode*lowestCommonAncestorOfBST(BinaryTreeNode*pNode, int nNodeOne, int nNodeTwo){
	if (pNode==NULL)
	{
	   return NULL;
	}
	if (pNode->m_nValue>nNodeOne && pNode->m_nValue>nNodeTwo)//当前节点的值大于这两个节点的值
	{
	return lowestCommonAncestorOfBST(pNode->m_pLeft, nNodeOne, nNodeTwo);//访问左子树
	}
	if (pNode->m_nValue<nNodeOne && pNode->m_nValue<nNodeTwo)//当前节点的值小于这两个节点的值
	{
	return lowestCommonAncestorOfBST(pNode->m_pRight, nNodeOne, nNodeTwo);//访问右子树
	}
	return pNode;//就是公共祖先
}
//二叉搜索树两个节点的最低公共祖先,参数为两个节点
BinaryTreeNode*lowestCommonAncestorOfBST(BinaryTreeNode*pNode, BinaryTreeNode*pNode1, BinaryTreeNode*pNode2){
	
	if (pNode==NULL)
	{
	return NULL;
	}
	if (pNode->m_nValue>pNode1->m_nValue && pNode->m_nValue>pNode2->m_nValue)//当前节点的值大于这两个节点的值
	{
	return lowestCommonAncestor(pNode->m_pLeft, pNode1, pNode2);//访问左子树
	}
	if (pNode->m_nValue<pNode1->m_nValue && pNode->m_nValue<pNode2->m_nValue)//当前节点的值小于这两个节点的值
	{
	return lowestCommonAncestor(pNode->m_pRight, pNode1, pNode2);//访问右子树
	}
	return pNode;//就是公共祖先
	
}

普通的二叉树:

Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree.
According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).”


_______3______
/              \
___5__          ___1__
/      \        /      \
6      _2       0       8
/  \
7   4
For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition.


思路:

我们可以用深度优先搜索,从叶子节点向上,标记子树中出现目标节点的情况。如果子树中有目标节点,标记为那个目标节点,如果没有,标记为null。显然,如果左子树、右子树都有标记,说明就已经找到最小公共祖先了。如果在根节点为p的左右子树中找p、q的公共祖先,则必定是p本身。

换个角度,可以这么想:如果一个节点左子树有两个目标节点中的一个,右子树没有,那这个节点肯定不是最小公共祖先。如果一个节点右子树有两个目标节点中的一个,左子树没有,那这个节点肯定也不是最小公共祖先。只有一个节点正好左子树有,右子树也有的时候,才是最小公共祖先。

代码如下:

//两个节点的最低公共祖先,参数为两个节点
BinaryTreeNode* lowestCommonAncestor(BinaryTreeNode*pNode, BinaryTreeNode*pNode1, BinaryTreeNode*pNode2){
	//发现目标节点则通过返回值标记该子树发现了某个目标结点
	if (pNode == NULL || pNode == pNode1 || pNode == pNode2) return pNode;
	//查看左子树中是否有目标结点,没有为null
	BinaryTreeNode*left = lowestCommonAncestor(pNode->m_pLeft, pNode1, pNode2);
	//查看右子树是否有目标节点,没有为null
	BinaryTreeNode*right = lowestCommonAncestor(pNode->m_pRight, pNode1, pNode2);
	//都不为空,说明做右子树都有目标结点,则公共祖先就是本身
	if (left != NULL&&right != NULL) return pNode;
	//如果发现了目标节点,则继续向上标记为该目标节点
	return left == NULL ? right : left;
}
//两个节点的最低公共祖先,参数为两个节点的值
BinaryTreeNode* lowestCommonAncestor(BinaryTreeNode*pNode, int nNodeOne, int nNodeTwo){
	//发现目标节点则通过返回值标记该子树发现了某个目标结点
	if (pNode == NULL || pNode->m_nValue == nNodeOne || pNode->m_nValue == nNodeTwo) return pNode;
	//查看左子树中是否有目标结点,没有为null
	BinaryTreeNode*left = lowestCommonAncestor(pNode->m_pLeft, nNodeOne, nNodeTwo);
	//查看右子树是否有目标节点,没有为null
	BinaryTreeNode*right = lowestCommonAncestor(pNode->m_pRight, nNodeOne, nNodeTwo);
	//都不为空,说明做右子树都有目标结点,则公共祖先就是本身
	if (left != NULL&&right != NULL) return pNode;
	//如果发现了目标节点,则继续向上标记为该目标节点
	return left == NULL ? right : left;
}

以如下的二叉树作为测试:

二叉搜索树                                                     普通的二叉树

             

下面是测试代码:

//先序创建二叉树  
void CreatBTree(BinaryTreeNode *&root)
{
	int nValue = 0;
	cin >> nValue;
	if (-1 == nValue)//-1代表为空
	{
		return;
	}
	else
	{
		root = new BinaryTreeNode();
		root->m_nValue = nValue;
		CreatBTree(root->m_pLeft);
		CreatBTree(root->m_pRight);
	}
}
int main(){
	BinaryTreeNode*T = NULL;
	BinaryTreeNode*pTreeOfBST = NULL;
	cout << "先序构建二叉树:" << endl;
	CreatBTree(T);
	cout << "先序构建二叉搜索树:" << endl;
	CreatBTree(pTreeOfBST);
	int nNodeOne, nNodeTwo;
	while (true)
	{
		cout << endl;
		cout <<"输入二叉搜索树两个节点:"<< endl;
		cin >> nNodeOne >> nNodeTwo;
		BinaryTreeNode*common = lowestCommonAncestorOfBST(pTreeOfBST, nNodeOne, nNodeTwo);
		cout << "二叉搜索树中两个节点的最低公共祖先为:" << endl;
		cout << common->m_nValue << endl;

		cout << "输入普通树两个节点:" << endl;
		cin >> nNodeOne >> nNodeTwo;
		common = lowestCommonAncestor(T, nNodeOne, nNodeTwo);
		cout << "普通树中两个节点的最低公共祖先为:" << endl;
		cout << common->m_nValue << endl;
	}
	return 0;
}


下面是输出结果:






  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值