您的位置:首页 > 其它

二叉树两个结点的最低共同父结点

2012-08-25 15:46 211 查看
输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。

网上看来的题目,以下都有参考。求数中两个结点的最低共同结点是面试中经常出现的一个问题。这个问题至少有两个变种。

第一变种是二叉树是一种特殊的二叉树:查找二叉树。也就是树是排序过的,位于左子树上的结点都比父结点小,而位于右子树的结点都比父结点大。我们只需要从根结点开始和两个结点进行比较。如果当前结点的值比两个结点都大,则最低的共同父结点一定在当前结点的左子树中。如果当前结点的值比两个结点都小,则最低的共同父结点一定在当前结点的右子树中。解法对应lastCommonParent_1。

第二个变种是树不一定是二叉树,每个结点都有一个指针指向它的父结点。

解法一:lastCommonParent_2

我们可以定义一函数,来判断一个结点的子树中是不是包含了另外一个结点。我们可以从根结点开始,判断以当前结点为根的树中左右子树是不是包含我们要找的两个结点。如果两个结点都出现在它的左子树中,那最低的共同父结点也出现在它的左子树中。如果两个结点都出现在它的右子树中,那最低的共同父结点也出现在它的右子树中。如果两个结点一个出现在左子树中,一个出现在右子树中,那当前的结点就是最低的共同父结点。接着我们来分析一下这个方法的效率。函数HasNode的本质就是遍历一棵树,其时间复杂度是O(n)(n是树中结点的数目)。由于我们根结点开始,要对每个结点调用函数HasNode。因此总的时间复杂度是O(n2)。不难发现我们判断以一个结点为根的树是否含有某个结点时,需要遍历树的每个结点。接下来我们判断左子结点或者右结点为根的树中是否含有要找结点,仍然需要遍历。第二次遍历的操作其实在前面的第一次遍历都做过了。由于存在重复的遍历,本方法在时间效率上肯定不是最好的。

解法二:lastCommonParent_3

我们可以从任何一个结点出发,得到一个到达树根结点的单向链表。因此这个问题转换为两个单向链表的第一个公共结点。

#include <iostream>
#include <list>
#include <assert.h>
using namespace std;

typedef struct BTreeNode
{
int value;
struct BTreeNode *left;
struct BTreeNode *right;
}BTreeNode, *BTree;
const int INVALIED = -1;

void createTree(int *tree, BTree &rt, int &i);
void preOrderRe(BTree rt);
bool hasNode(BTree rt, BTreeNode *pNode); //以rt为根节点的树是否含有子节点pNode
bool getNodePath(BTree rt, BTreeNode *pNode, list<BTreeNode *> &path); //与按叶子节点访问差不多,用bool类型做为返回值是为了当找到时马上结束递归
BTreeNode* lastCommonParent_1(BTree rt, BTreeNode *pNode1, BTreeNode *pNode2); //查找树的时候
BTreeNode* lastCommonParent_2(BTree rt, BTreeNode *pNode1, BTreeNode *pNode2); //一般的二叉树的算法一
BTreeNode* lastCommonParent_3(BTree rt, BTreeNode *pNode1, BTreeNode *pNode2); //一般的二叉树的算法二

int main()
{
int tree[] = {10, 8, 6, 4, -1, -1, -1, 9, -1, -1, 12, 11, -1, -1, 13, -1, -1};
BTree rt = NULL;
int i = 0;
createTree(tree, rt, i);
BTreeNode *pNode1 = rt->left->left->left;
BTreeNode *pNode2 = rt->left->right;
BTreeNode *pCommon = NULL;
//pCommon = lastCommonParent_1(rt, pNode1, pNode2);
//pCommon = lastCommonParent_2(rt, pNode1, pNode2);
pCommon = lastCommonParent_3(rt, pNode1, pNode2);
cout<<pCommon->value<<endl;
//preOrderRe(rt);
//printf("\n");
return 0;
}

void createTree(int *tree, BTree &rt, int &i)
{
int val = tree[i++];
if(val == INVALIED)
{
rt = NULL;
return;
}
rt = (BTreeNode *)malloc(sizeof(BTreeNode));
rt->value = val;
createTree(tree, rt->left, i);
createTree(tree, rt->right, i);
}

void preOrderRe(BTree rt)
{
if(rt)
{
printf("%d\t", rt->value);
preOrderRe(rt->left);
preOrderRe(rt->right);
}
}

BTreeNode* lastCommonParent_1(BTree rt, BTreeNode *pNode1, BTreeNode *pNode2)
{
if(pNode1->value > rt->value && pNode2->value < rt->value)
return rt;
if(pNode1->value < rt->value && pNode2->value > rt->value)
return rt;
if(pNode1->value < rt->value && pNode2->value < rt->value)
return lastCommonParent_1(rt->left, pNode1, pNode2);
if(pNode1->value > rt->value && pNode2->value > rt->value)
return lastCommonParent_1(rt->right, pNode1, pNode2);
}

bool hasNode(BTree rt, BTreeNode *pNode)
{
if(rt == pNode)
return true;
bool ret = false;
if(rt->left)
ret = hasNode(rt->left, pNode);
if(!ret && rt->right)
ret = hasNode(rt->right, pNode);
return ret;
}

BTreeNode* lastCommonParent_2(BTree rt, BTreeNode *pNode1, BTreeNode *pNode2)
{
assert(rt != NULL && pNode1 != NULL && pNode2 != NULL);
if(rt == pNode1 || rt == pNode2)
return rt;
bool pNode1LeftHas = false;
bool pNode2LeftHas= false;
if(rt->left)
{
pNode1LeftHas = hasNode(rt->left, pNode1);
pNode2LeftHas = hasNode(rt->left, pNode2);
}
if((pNode1LeftHas == true && pNode2LeftHas == false)||(pNode1LeftHas == false && pNode2LeftHas == true))
return rt;
if(pNode1LeftHas == true && pNode2LeftHas == true)
return lastCommonParent_2(rt->left, pNode1, pNode2);
if(rt->right && pNode1LeftHas == false && pNode2LeftHas == false)
return lastCommonParent_2(rt->right, pNode1, pNode2);
}

bool getNodePath(BTree rt, BTreeNode *pNode, list<BTreeNode *> &path)
{
if(rt == NULL)
return false;
if(rt == pNode)
return true;
path.push_back(rt);
bool ret = false;
if(rt->left)
ret = getNodePath(rt->left, pNode, path);
if(!ret && rt->right)
ret = getNodePath(rt->right, pNode, path);
if(!ret)
path.pop_back(); //这个容易错,在哪里pop,当一个节点的左右节点都检查完后在pop
return ret;
}

BTreeNode* lastCommonParent_3(BTree rt, BTreeNode *pNode1, BTreeNode *pNode2)
{
list<BTreeNode *> path1;
getNodePath(rt, pNode1, path1);
list<BTreeNode *> path2;
getNodePath(rt, pNode2, path2);

list<BTreeNode *>::const_iterator iter1 = path1.begin();
list<BTreeNode *>::const_iterator iter2 = path2.begin();

BTreeNode *ret = NULL;
while(iter1 != path1.end() && iter2!= path2.end())
{
if(*iter1 == *iter2)
ret = *iter1;
iter1++;
iter2++;
}
return ret;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: