您的位置:首页 > 其它

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

2017-07-28 22:21 369 查看
要求考虑以下三种种情况,给出解决方案,并解决:

1:二叉树每个节点有parent(三叉链)

2:二叉树是搜索二叉树。

3:就是普通二叉树。(尽可能实现时间复杂度为O(N))

求两个结点的最近公共祖先有两种情况。

1、如果这两个结点不在一条线上,则它们就分别在最近的公共祖父的左右子树上。

2、如果这两个结点在一条线上,则它们之中深度最前的就是他们的最近的公共祖先。

1:三叉链。在这种情况下,我们可以分别用两个数据结构来保存两个节点到根节点的路径,然后通过对比,找到最近公共祖先。

/*
//三叉链
struct Node
{
int _data;
Node* _left;
Node* _right;
Node* _parent;
Node(const int& x)
: _data(x)
, _left(NULL)
, _right(NULL)
, _parent(NULL)
{}
};
*/
Node* GetLastestCommonAncestor4(Node* root, Node* x1, Node* x2)
{
assert(x1 && x2);
if (root == NULL)
return NULL;

stack<Node*> s1;
stack<Node*> s2;

//x1
Node* cur1 = x1;
while (cur1->_parent)
{
s1.push(cur1);
cur1 = cur1->_parent;
}

//x2
Node* cur2 = x2;
while (cur2->_parent)
{
s2.push(cur2);
cur2 = cur2->_parent;
}

//走到这里,两个栈中分别保存了x1和x2到根节点的路径
while (s1.size() != s2.size())
{
if (s1.size() > s2.size())
s1.pop();
else
s2.pop();
}

while (!s1.empty() && !s2.empty() && s1.top() != s2.top())
{
s1.pop();
s2.pop();
}

if (s1.top() == s2.top())
return s1.top();
return NULL;
}


2:二叉树是搜索二叉树,对于搜索树来说,左子树的节点都比根节点小,右子树的节点都比根节点大。根据搜索树这样的特征,我们可以有以下思路。

(1)如果一个节点比根节点小,另一个节点比根节点大, 则根节点为最近公共祖先;

(2)如果两个节点均比根节点小,则最近公共祖先在左子树;

(3)如果两个节点均比根节点大,则最近公共祖先在右子树。

有了这样的思路,我们可以通过递归,实现查找最近公共祖先。

struct Node
{
int _data;
Node* _left;
Node* _right;
Node(const int& x)
: _data(x)
, _left(NULL)
, _right(NULL)
{}
};

Node* GetLastestCommonAncestor1(Node* root, Node* x1, Node* x2)
{
assert(x1&&x2);
if (root == NULL)
return NULL;
if ((x1->_data <= root->_data&&x2->_data >= root->_data)
|| (x1->_data >= root->_data&&x2->_data <= root->_data))
return root;
else if (x1->_data < root->_data&&x2->_data < root->_data)
return GetLastestCommonAncestor1(root->_left, x1, x2);
else
return GetLastestCommonAncestor1(root->_right, x1, x1);
}


3:普通二叉树

可以分别使用上面两种特殊情况的思想来处理普通二叉树

struct Node
{
int _data;
Node* _left;
Node* _right;
Node(const int& x)
: _data(x)
, _left(NULL)
, _right(NULL)
{}
};

//普通二叉树(搜索二叉树思想)
bool IsInTree(Node* root, Node* x)
{
if (root == NULL)
return false;
if (root->_data == x->_data)
return true;
else
return IsInTree(root->_left, x) || IsInTree(root->_right, x);
}

Node* GetLastestCommonAncestor2(Node* root, Node* x1, Node* x2)
{
assert(x1 && x2);
if (root == NULL)
return NULL;
bool x1InLeft, x1InRight, x2InLeft, x2InRight;
x1InLeft = IsInTree(root->_left, x1);
x1InRight = IsInTree(root->_right, x1);
assert(x1InLeft || x1InRight);

x2InLeft = IsInTree(root->_left, x2);
x2InRight = IsInTree(root->_right, x2);
assert(x2InLeft || x2InRight);

if ((x1InLeft && x2InRight) || (x1InRight && x2InLeft))
return root;
else if (x1InLeft&&x2InLeft)
return GetLastestCommonAncestor2(root->_left, x1, x2);
else
return GetLastestCommonAncestor2(root->_right, x2, x2);
}

//普通二叉树(三叉链方法的思想)
bool GetNodePaths(Node* root, Node* x, stack<Node*>& s)
{
if (root == NULL)
return;
s.push(root);
if (root == x)
return true;
bool inLeft = GetNodePaths(root->_left, x, s);
if (inLeft)
return true;
bool inRight = GetNodePaths(root->_right, x, s);
if (inRight)
return true;
s.pop();
return false;
}

Node* GetLastestCommonAncestor3(Node* root, Node* x1, Node* x2)
{
assert(x1&&x2);
if (root == NULL)
return NULL;
stack<Node*> paths1, paths2;
if (!GetNodePaths(root, x1, paths1)   || !GetNodePaths(root, x2, paths2))
return NULL;

while (paths1.size() != paths2.size())
{
if (paths1.size() > paths2.size())
paths1.pop();
else
paths2.pop();
}

while (!paths1.empty() && !paths2.empty() && paths1.top() != paths2.top())
{
paths1.pop();
paths2.pop();
}

if (paths1.top() == paths2.top())
return paths1.top();
return NULL;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐