hammar's answerが示すように、多くの操作が繰り返されるため、アルゴリズムは非常に非効率的です。
私は別のアプローチを行います: 2 つの指定されたノードが同じサブツリーにない場合 (したがって、最初の共通の祖先になる)、すべての潜在的なルート ノードをテストする代わりに、ルートから指定された 2 つのノードへのパスを決定します。ノードを比較します。ルートから下にあるパス上の最後の共通ノードは、最初の共通祖先でもあります。
Java での (テストされていない) 実装を次に示します。
private List<Tree> pathToNode(Tree root, Tree node) {
List<Tree> path = new LinkedList<Tree>(), tmp;
// root is wanted node
if (root == node) return path;
// check if left child of root is wanted node
if (root.left == node) {
path.add(node);
path.add(root.left);
return path;
}
// check if right child of root is wanted node
if (root.right == node) {
path.add(node);
path.add(root.right);
return path;
}
// find path to node in left sub-tree
tmp = pathToNode(root.left, node);
if (tmp != null && tmp.size() > 1) {
// path to node found; add result of recursion to current path
path = tmp;
path.add(0, node);
return path;
}
// find path to node in right sub-tree
tmp = pathToNode(root.right, node);
if (tmp != null && tmp.size() > 1) {
// path to node found; add result of recursion to current path
path = tmp;
path.add(0, node);
return path;
}
return null;
}
public Tree commonAncestor(Tree root, Tree p, Tree q) {
List<Tree> pathToP = pathToNode(root, p),
pathToQ = pathToNode(root, q);
// check whether both paths exist
if (pathToP == null || pathToQ == null) return null;
// walk both paths in parallel until the nodes differ
while (iterP.hasNext() && iterQ.hasNext() && iterP.next() == iterQ.next());
// return the previous matching node
return iterP.previous();
}
pathToNode
との両方commonAncestor
が O(n) にあります。