简体   繁体   中英

Find the lowest common ancestor of two nodes from adjacency list

If I know the adjacency list of each node present in a tree, then how do I find out the lowest common ancestor of any two nodes present in that tree?

Actually I want to find out the distance between any two nodes, so I want to compute the LCA. Is there any way to compute it from the adjacency list?

The LCA of n1 and n2 in T is the shared ancestor of n1 and n2 that is located farthest from the root. Computation of lowest common ancestors may be useful, for instance, as part of a procedure for determining the distance between pairs of nodes in a tree: the distance from n1 to n2 can be computed as the distance from the root to n1, plus the distance from the root to n2, minus twice the distance from the root to their lowest common ancestor. ( Source Wiki )

The fact that we're dealing with an adjacency list doesn't really change the problem.

The basic idea to find the LCA of nodes A and B is as follows:

  • Start from the root.
  • If a child's subtree contains both A and B, return the LCA of that subtree.
  • If a child contains A and another child contains B.

The above checks can fairly easy be incorporated into a single function by returning an indicator for whichever case.

In an unordered tree, you have to explore the entire tree in the worst case, but in a Binary Search Tree, you can easily check whether a left or right subtree could contain a node by simply comparing its value with the current node.

But really you shouldn't use an LCA algorithm to determine the distance. You should instead modify the above to return the distance instead of the LCA. The modification to do this is reasonably simple:

  • When you've already found the distance in a child's subtree, just return it.
  • If you've found both A and B in separate children's subtrees, return the distance between A and B.
  • If you've only found either A or B in a child's subtree, just return the distance to A or B with an indicator to say what you're returning.

You may try something like:

class Node
{
public:
    // Other stuff.
    const Node* getParent() const { return parent; }
private:
    Node* parent;
    std::vector<Node*> children;
};

const Node* getLowestCommonAncestor(const Node& lhs, const Node& rhs)
{
    for (const Node* node1 = &lhs; node1 != nullptr; node1 = node1->getParent()) {
        for (const Node* node2 = &rhs; node2 != nullptr; node2 = node2->getParent()) {
            if (node1 == node2) {
                return node1;
            }
        }
    }
    return nullptr;
}

or, if you don't have parent:

namespace detail
{
    struct LCAFlag {
        enum { NoFound = 0, leftFound = 1, rightFound = 2 };
    };

    const Node* getLCA_Rec(const Node& root, const Node& lhs, const Node& rhs, unsigned int& flag)
    {
        if (&root == &lhs) {
            flag |= LCAFlag::leftFound;
        } else if (&root == &rhs) {
            flag |= LCAFlag::rightFound;
        }
        if (flag == (LCAFlag::leftFound | LCAFlag::rightFound)) {
            return nullptr; // both found. parent is the LCA
        }
        for (auto it = root.children.begin(); it != root.children.end(); ++it) {
            const Node* res = getLCA_Rec(**it, lhs, rhs, flag);

            if (res != nullptr) {
                return res;
            }
            if (flag == (LCAFlag::leftFound | LCAFlag::rightFound)) {
                return &root;
            }
        }
        return nullptr;
    }
}
const Node* getLCA(const Node& root, const Node& lhs, const Node& rhs)
{
    unsigned int flag = detail::LCAFlag::NoFound;
    return detail::getLCA_Rec(root, lhs, rhs, flag);
}
  1. Keep the height (distance from root) of each node.
  2. If the two nodes have different height, walk up from the deeper node until we've got nodes on the same level.
  3. If the two nodes are equal, then we've got our answers. If not, go up another level and repeat.

This assumes that your tree are a rooted one, and that you can accommodate a bit of extra spaces to store the height and parent pointer of each node.

The efficiency of this algorithm is O(height), so it depends on how balanced the tree is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM