构建一棵二叉树(不一定是二叉查找树),求出该二叉树中某两个结点的最低公共父结点。借用一张图如下:
结点8 和 结点5 的最低公共父结点为 结点2
如果是二叉搜索树的话,那就很简单,如果两个节点的值在左边,则找左子树,在右边,则找右子树,若一左一右,则找到了这个节点
不是二叉查找树的话,那么有两种方法
利用遍历序列
有两种思路,一种是通过中序遍历和后序遍历。由于中序遍历是先左子树中的结点,再访问根,再访问右子树中结点,因此这两个结点的公共父结点一定处于这两个结点之间。
如:
- 中序遍历:8, 4, 9, 2, 5, 1, 6, 3, 7 结点2处于结点8 和 结点5 之间,也就是说:结点8 和 结点5 的最低公共父结点在 [8~5]之间的候选结点,这里为{4,9,2}中取
- 后序遍历是先访问左右子树中的结点,最后再访问根。故这两个结点的最低公共父结点一定处于 结点8 和 结点5 之后的结点,且是第一个出现在{4,9,2}中的那个结点。后序遍历:8, 9, 4, 5, 2, 6, 7, 3, 1 8->9->4->5 这之后的结点,才可能是 结点8 和 结点5 的父结点。
利用递归
情况一:如果左子树查找出的公共节点是NULL,则表明从左子树根节点开始到左子树的所有叶子节点等所有节点中,没有找到两个节点中的任何一个,这就说明,这两个节点不在左子树上,不在左子树,则必定在右子树上;
情况二:如果右子树查找的公共节点是NULL,说明在右子树中无法找到任何一个节点,则两个节点必定在左子树上;
情况三: 如果左右子树查找的公共节点都不是NULL,说明左右子树中各包含一个节点,则当前节点pRoot就是最低公共节点,返回就可以了。
三种情况是互斥的, 只能是其中之一。
BTreeNode_t *GetLastCommonParent( BTreeNode_t *pRoot, BTreeNode_t *pNode1, BTreeNode_t *pNode2){
if( pRoot == NULL ) //说明是空树,不用查找了,也就找不到对应节点,则返回NULL
return NULL;
if( pRoot == pNode1 || pRoot == pNode2 )//说明在当前子树的根节点上找到两个节点之一
return pRoot;
BTreeNode_t *pLeft = GetLastCommonParent( pRoot->m_pLeft, pNode1, pNode2); //左子树中的查找两个节点并返回查找结果
BTreeNode_t *pRight = GetLastCommonParent( pRoot->m_pRight, pNode1, pNode2);//右子树中查找两个节点并返回查找结果
if( pLeft == NULL )//如果在左子树中没有找到,则断定两个节点都在右子树中,可以返回右子树中查询结果;否则,需要结合左右子树查询结果共同断定
return pRight;
if ( pRight == NULL )//如果在右子树中没有找到,则断定两个节点都在左子树中,可以返回左子树中查询结果;否则,需要结合左右子树查询结果共同断定
return pLeft;
return pRoot;//如果在左右子树中都找两个节点之一,则pRoot就是最低公共祖先节点,返回即可。
}