簡體   English   中英

從鄰接表中找到兩個節點的最低共同祖先

[英]Find the lowest common ancestor of two nodes from adjacency list

如果我知道樹中存在的每個節點的鄰接列表,那么我如何找出該樹中存在的任何兩個節點的最低共同祖先?

實際上,我想找出任意兩個節點之間的距離,因此我想計算LCA。 有什么方法可以從鄰接表中計算出來嗎?

T中的n1和n2的LCA是距離根最遠的n1和n2的共享祖先。 最低共同祖先的計算可能有用,例如,作為確定樹中節點對之間距離的過程的一部分:從n1到n2的距離可以計算為從根到n1的距離加上距離從根到n2,減去從根到其最低共同祖先的距離的兩倍。 來源維基

我們正在處理鄰接表的事實並不能真正解決問題。

查找節點A和B的LCA的基本思路如下:

  • 從根開始。
  • 如果孩子的子樹同時包含A和B,則返回該子樹的LCA。
  • 如果一個孩子包含A,另一個孩子包含B。

無論哪種情況,都可以通過返回指示符將上述檢查相當容易地合並到單個函數中。

在無序樹中,必須在最壞的情況下瀏覽整個樹,但是在二叉搜索樹中,只需將其值與當前節點進行比較,就可以輕松地檢查左或右子樹是否可以包含一個節點。

但實際上您不應該使用LCA算法來確定距離。 您應該修改以上內容以返回距離而不是LCA。 對此的修改相當簡單:

  • 在孩子的子樹中找到距離后,只需返回即可。
  • 如果在單獨的子樹中找到了A和B,則返回A和B之間的距離。
  • 如果您僅在孩子的子樹中找到A或B,只需將距離返回到A或B,並附上指示符即可說明您要返回的內容。

您可以嘗試以下方法:

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;
}

或者,如果您沒有父母:

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. 保持每個節點的高度(與根的距離)。
  2. 如果兩個節點的高度不同,請從較深的節點上走,直到節點處於同一水平。
  3. 如果兩個節點相等,那么我們就得到了答案。 如果沒有,請再上一層然后重復。

這假設您的樹是一棵有的樹,並且您可以容納一些額外的空間來存儲每個節點的高度和父指針。

該算法的效率為O(height),因此它取決於樹的平衡程度。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM