1. 如果只有一次查询,参考 http://www.geeksforgeeks.org/lowest-common-ancestor-binary-tree-set-1/的解法。
代码如下:
TreeNode* LCAcommon(TreeNode *root, TreeNode *n1, TreeNode* n2)
{
if(root == NULL) return NULL;
if(root == n1 || root == n2) return root;
TreeNode *lca_left = LCAcommon(root->left, n1, n2);
TreeNode *lca_right = LCAcommon(root->right, n1, n2);
if(lca_left && lca_right) return root;
if(lca_left)
return lca_left;
else
return lca_right;
}
如果不能确定要查询的两个点是否存在,可以使用以下的代码进行判断,如果有一个节点不存在,则需要返回null。
// This function returns pointer to LCA of two given values n1 and n2.
// v1 is set as true by this function if n1 is found
// v2 is set as true by this function if n2 is found
struct Node *findLCAUtil(struct Node* root, int n1, int n2, bool &v1, bool &v2)
{
// Base case
if (root == NULL) return NULL;
// If either n1 or n2 matches with root's key, report the presence
// by setting v1 or v2 as true and return root (Note that if a key
// is ancestor of other, then the ancestor key becomes LCA)
if (root->key == n1)
{
v1 = true;
return root;
}
if (root->key == n2)
{
v2 = true;
return root;
}
// Look for keys in left and right subtrees
Node *left_lca = findLCAUtil(root->left, n1, n2, v1, v2);
Node *right_lca = findLCAUtil(root->right, n1, n2, v1, v2);
// If both of the above calls return Non-NULL, then one key
// is present in once subtree and other is present in other,
// So this node is the LCA
if (left_lca && right_lca) return root;
// Otherwise check if left subtree or right subtree is LCA
return (left_lca != NULL)? left_lca: right_lca;
}
// Returns true if key k is present in tree rooted with root
bool find(Node *root, int k)
{
// Base Case
if (root == NULL)
return false;
// If key is present at root, or in left subtree or right subtree,
// return true;
if (root->key == k || find(root->left, k) || find(root->right, k))
return true;
// Else return false
return false;
}
// This function returns LCA of n1 and n2 only if both n1 and n2 are present
// in tree, otherwise returns NULL;
Node *findLCA(Node *root, int n1, int n2)
{
// Initialize n1 and n2 as not visited
bool v1 = false, v2 = false;
// Find lca of n1 and n2 using the technique discussed above
Node *lca = findLCAUtil(root, n1, n2, v1, v2);
// Return LCA only if both n1 and n2 are present in tree
if (v1 && v2 || v1 && find(lca, n2) || v2 && find(lca, n1))
return lca;
// Else return NULL
return NULL;
}
2. 如果有多次查询,可以使用Trajan算法,使用Union Set 进行预处理。
参考: http://en.wikipedia.org/wiki/Tarjan%27s_off-line_lowest_common_ancestors_algorithm
http://scturtle.is-programmer.com/posts/30055.html
算法代码:
<pre name="code" class="cpp">#include <iostream>
#include <map>
#include <vector>
using namespace std;
struct TreeNode
{
TreeNode *left;
TreeNode *right;
int val;
TreeNode(int _val): val(_val) {}
};
//for union set
map<TreeNode*, TreeNode*> parent;
map<TreeNode*, int> rank;
//for LCA algorithm
map<TreeNode*, TreeNode*> ancestor;
map<TreeNode*, bool> visited;
void MakeSet(TreeNode* root)
{
parent[root] = root;
rank[root] = 0;
}
TreeNode* FindSet(TreeNode *node)
{
if(parent[node] == node)
return node;
parent[node] = FindSet(parent[node]);
return parent[node];
}
void Union(TreeNode *node1, TreeNode *node2)
{
TreeNode* root1 = FindSet(node1);
TreeNode* root2 = FindSet(node2);
if(root1 == root2) return;
int rank1 = rank[root1];
int rank2 = rank[root2];
if(rank1 > rank2)
parent[root2] = root1;
else
{
parent[root1] = root2;
if(rank1 == rank2)
rank[root2]++;
}
}
void LCATrajan(TreeNode *root, vector<pair<TreeNode*, TreeNode*> > &query)
{
MakeSet(root);
ancestor[FindSet(root)] = root;
if(root->left)
{
LCATrajan(root->left, query);
Union(root->left, root);
ancestor[FindSet(root->left)] = root;
}
if(root->right)
{
LCATrajan(root->right, query);
Union(root->right, root);
ancestor[FindSet(root->right)] = root;
}
visited[root] = true;
for(int i=0; i<query.size(); i++)
{
TreeNode *first = query[i].first;
TreeNode *second = query[i].second;
if(first == root && visited[second] == true)
{
cout << (first->val) << " " << (second->val)
<< " " << ancestor[FindSet(second)]->val << endl;
}
else if(second == root && visited[first] == true)
{
cout << (first->val) << " " << (second->val)
<< " " << ancestor[FindSet(first)]->val << endl;
}
}
}
int main()
{
// Let us create binary tree given in the above example
TreeNode * root = new TreeNode(1);
TreeNode *t2 = new TreeNode(2);
TreeNode *t3 = new TreeNode(3);
TreeNode *t4 = new TreeNode(4);
TreeNode *t5 = new TreeNode(5);
TreeNode *t6 = new TreeNode(6);
TreeNode *t7 = new TreeNode(7);
root->left = t2;
root->right = t3;
root->left->left = t4;
root->left->right = t5;
root->right->left = t6;
root->right->right = t7;
vector<pair<TreeNode*, TreeNode*> > query;
query.push_back(make_pair(t4, t5));
query.push_back(make_pair(t4, t6));
query.push_back(make_pair(t4, t3));
query.push_back(make_pair(t2, t4));
LCATrajan(root, query);
return 0;
}