【问题标题】:Algorithm finding path in an undirected tree在无向树中寻找路径的算法
【发布时间】:2011-01-22 10:27:57
【问题描述】:

假设给定一棵无向树,我需要在两个节点之间找到一条路径(唯一路径)。

最好的算法是什么。我可能可以使用 Dijkstra 算法,但对于树来说可能有更好的算法。

C++ 示例会有所帮助,但不是必需的

谢谢

【问题讨论】:

  • 你的意思是找到 THE 路径。除非您允许路径多次遍历同一个节点,否则树中只有一个从节点到另一个节点的路径(实际上这是树的可能定义之一)
  • 我发布了一个答案,假设您也对部分“向上”的路径感兴趣,即使您的表示中没有指向节点的父节点的链接。这在问题中确实不清楚......

标签: c++ algorithm graph tree


【解决方案1】:

假设每个节点都有一个指向其父节点的指针,然后简单地从每个起始节点向后跟踪树到根节点。最终,两条路径必须相交。交叉点测试可以像维护一个std::map 的节点地址一样简单。

更新

由于您已更新问题以指定 无向 树,因此上述内容无效。一个简单的方法是从节点 #1 开始执行深度优先遍历,最终您将到达节点 #2。这是树的大小O(n)。假设一棵完全通用的树,我不确定是否会有比这更快的方法。

【讨论】:

  • 我说的是无向树
  • @Yakov:嗯,是的,这显然会有所作为!很高兴看到您相应地更新了您的问题。
【解决方案2】:

广度优先搜索和深度优先搜索比 Dijkstra 算法更有效。

【讨论】:

  • 如果所有边权重都是一个(或更一般地相同),Dijksta 的算法是否与广度优先搜索相同?
  • 不是。如果您使用 Dijkstra,则必须选择最近的未访问交叉路口(速度很慢)。因此,如果使用斐波那契堆提取最小值,则复杂度为 O(E + V logV),E - 边,V - 顶点。如果使用广度优先搜索,复杂度为 O(E+V) = O(V)(它是一棵树,所以 E = V - 1)。
【解决方案3】:

假设你有

struct Node
{
    std::vector<Node *> children;
};

那么可以做的是从根开始遍历整个树,在遍历期间保持整个链。如果你发现例如node1 然后保存当前链,如果找到 node2 然后检查交叉点...在代码中(UNTESTED):

bool findPath(std::vector<Node *>& current_path, // back() is node being visited
              Node *n1, Node *n2,                // interesting nodes
              std::vector<Node *>& match,        // if not empty back() is n1/n2
              std::vector<Node *>& result)       // where to store the result
{
    if (current_path.back() == n1 || current_path.back() == n2)
    {
        // This is an interesting node...
        if (match.size())
        {
            // Now is easy: current_path/match are paths from root to n1/n2
            ...
            return true;
        }
        else
        {
            // This is the first interesting node found
            match = current_path;
        }
    }
    for (std::vector<Node *>::iterator i=current_path.back().children.begin(),
                                       e=current_path.back().children.end();
         i != e; ++i)
    {
        current_path.push_back(*i);
        if (findPath(current_path, n1, n2, match, result))
          return true;
        current_path.pop_back(); // *i
    }
    return false;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-23
    • 2012-10-24
    • 2021-12-18
    • 2010-12-31
    • 1970-01-01
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多