求二叉树中两个节点的最低公共祖先节点

数据结构 同时被 2 个专栏收录
75 篇文章 0 订阅
21 篇文章 0 订阅

本篇博客接着写二叉树的面试题中:二叉树面试题(一)   二叉树面试题(二)  

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

这个题可能有几种不同的条件,那这样就是不同的问题

(1) 树是二叉树,且是二叉搜索树。

思路:如果是二叉搜索树,二叉搜索树是排序过的,位于左子树的节点都比父节点小,位于右子树的节点都比父节点大。我们只需要从树的根节点开始和两个输入的节点进行比较。如果当前节点的值比两个节点的值都大,最低公共祖先结点一定在当前结点的右子树。如果当前节点的值比两个节点的值都,最低公共祖先节点一定在当前结点的左子树。

如果一个结点比当前结点大,一个比 当前结点小,则最低公共祖先节点为当前结点。

代码:

BinaryTreeNode<T>* GetLastCommomParent(BinaryTreeNode<T>* pRoot,int data1,int data2)
{
	if (pRoot)
	{
		if (data1 < pRoot->_data && data2 < pRoot->_data)
			return GetLastCommomParent(pRoot->_pLeftChild,data1,data2);
		else if (data1 > pRoot->_data && data2 > pRoot->_data)
			return GetLastCommomParent(pRoot->_pRightChild, data1, data2);
		else
			return pRoot;
	}
	return NULL;
}

(2) 树的结点有指向父节点的指针

这个问题可以转换为求两个链表的第一个公共节点。


从树的每一个叶子节点开始都有一个由指向父节点的指针串起来的链表,这些链表的尾指针都是树的根节点。
输入两个节点,那么这两个节点位于两个链表上,他们的最低公共祖先刚好就是这两个链表的第一个公共节点。
比如输入F和H,F在链表F-D-B-A上,而H在链表H-E-B-A上,这两个链表的第一个交点B刚好也是它们的最低公共祖先

(3)没有指向父节点的指针

用两个链表分别保存从根节点到输入的两个节点的路径,然后把问题转换成两个链表的最后公共节点。



  

递归解法:
(1)如果两个节点分别在根节点的左子树和右子树,则返回根节点
(2)如果两个节点都在左子树,则递归处理左子树;如果两个节点都在右子树,则递归处理右子树

代码:

template<class T>
bool FindNode(BinaryTreeNode<T> * pRoot,BinaryTreeNode<T> *pNode)
{
	if (pRoot == NULL || pNode == NULL)
		return false;
	if (pRoot == pNode)
		return true;
	bool found = FindNode(pRoot->_pLeftChild,pNode);
	if (!found)
		return FindNode(pRoot->_pRightChild,pNode);
}
template<class T>
BinaryTreeNode<T>* GetLastCommomParent(BinaryTreeNode<T>* pRoot, BinaryTreeNode<T>* pNode1, BinaryTreeNode<T>* pNode2)
{
	if (FindNode(pRoot->_pLeftChild, pNode1))
	{
		if (FindNode(pRoot->_pRightChild, pNode2))
			return pRoot;
		else
			return GetLastCommomParent(pRoot->_pLeftChild,pNode1,pNode2);
	}
	else
	{
		if (FindNode(pRoot->_pLeftChild, pNode2))
			return pRoot;
		else
			return GetLastCommomParent(pRoot->_pRightChild,pNode1,pNode2);
	}
}

(2)非递归解法

先求从根节点到两个节点的路径,然后再比较对应路径的节点就行,最后一个相同的节点也就是他们在二叉树中的最低公共祖先节点

template<class T>
bool GetPath(BinaryTreeNode<T>* pRoot,BinaryTreeNode<T>* pNode,list<BinaryTreeNode<T>*>& path)
{
	if (pRoot == NULL || pNode == NULL)
		return  false;
	path.push_back(pRoot);
	if (pRoot == pNode)
		return true;
	bool found = false;
	found = GetPath(pRoot->_pLeftChild,pNode,path);
	if (!found)
		found = GetPath(pRoot->_pRightChild,pNode,path);
	if (!found)
		path.pop_back();
	return found;
}
template<class T>
BinaryTreeNode<T>* GetLastCommomAcess(BinaryTreeNode<T>* pRoot, BinaryTreeNode<T>* pNode1, BinaryTreeNode<T>* pNode2)
{
	if (pRoot == NULL || pNode1 == NULL || pNode2 == NULL)
		return NULL;
	list<BinaryTreeNode<T>*> path1;
	bool res1 = GetPath(pRoot,pNode1,path1);
	list<BinaryTreeNode<T>*> path2;
	bool res2 = GetPath(pRoot, pNode2, path2);
	if (!res1 || !res2)
		return NULL;
	//求两个链表的公共节点
	BinaryTreeNode<T>* Ancestor = NULL;
	list<BinaryTreeNode<T>*>::const_iterator iter1 = path1.end();
	list<BinaryTreeNode<T>*>::const_iterator iter2 = path2.end() ;
	while (--iter1 != path1.begin() && --iter2 != path2.begin())
	{
		if (*iter1 == *iter2)
		{
			Ancestor = *iter1;
			break;
		}
	}
	return Ancestor;
}


  • 2
    点赞
  • 1
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值