【问题标题】:Algorithm to clone a graph克隆图的算法
【发布时间】:2019-01-16 14:51:53
【问题描述】:

克隆一棵树的算法非常简单,我们可以为此进行前序遍历。是否有一种有效的算法来克隆图?

我尝试了类似的方法,并得出结论,我们需要维护一个已添加到新图中的节点的哈希映射,否则会出现节点重复,因为一个节点可以有多个父节点。

【问题讨论】:

  • 修改了 bfs/dfs,节点被标记为“已访问”时被复制?
  • 很大程度上依赖于数据结构。
  • Graph traversal 在维基百科上。相对较大的文章,可能会给你一些东西。
  • @Zeta 假设图表示为邻接矩阵
  • @Keyser DFS/BFS 在原始图中带有标志将帮助我不再访问该节点。但在新图中,我确实想要当前节点和图中已添加的节点之间的链接。由于已经添加的节点有多个父节点。把它想象成一些社交网络图,在其中你会有共同的朋友。

标签: algorithm clone graph-algorithm


【解决方案1】:

进行深度优先搜索并在访问每个节点时复制它就足够了。正如您所说,您需要某种方式将原始图中的节点映射到相应的副本,以便循环和交叉边的副本可以正确连接。

这个映射也足以记住 DFS 中已经访问过的节点。

所以在 Java 中你会有类似的东西:

class Node {

  // Contents of node...
  Data data;

  // ... member declarations like array of adjacent nodes
  final ArrayList<Node> children = new ArrayList<>();

  // Recursive graph walker for copying, not called by others.
  private Node deepCloneImpl(Map<Node, Node> copies) {
    Node copy = copies.get(this);
    if (copy == null) {
      copy = new Node(data);
      // Map the new node _before_ copying children.
      copies.put(this, copy);
      for (Node child : children)
        copy.children.add(child.deepCloneImpl(copies));
    }
    return copy;
  }

  public Node deepClone() {
    return deepCloneImpl(new HashMap<Node, Node>());
  }
}

请注意,您想要覆盖equalshashCodeNode。包含副本的映射依赖于 Object 定义的引用相等性。

另一种方法是在每个节点中放置一个附加字段,如果有则指向副本,否则为空。这只是通过另一种方法实现地图。但它需要两次遍历图表:一次制作副本,另一次清除这些地图字段以供将来重用。

【讨论】:

    【解决方案2】:

    如果您有某种快速唯一标识每个节点的方法,您的哈希映射方法似乎是可行的。

    否则,您最好:

    1. 使用数据结构存储图形,允许您直接在每个节点中存储“重复”唯一标志(例如,0 不重复,1 到 @ 987654323@ 重复节点),

    2. 遍历节点(通过 BFS、DFS)处理已经重复的节点从起始图重建所有连接

      李>

    您的起始图和结束图都应该在每个节点中都有相应的唯一“重复”标志,以便您能够正确地从起始图重建连接。当然,您可以使用“重复”标志和“唯一标识符”作为单独的变量。

    【讨论】:

      【解决方案3】:

      当您从源图中复制节点时,将每个节点放置在 &lt;Node, Integer&gt; 映射中(从而将节点编号从 1 到 N)。

      在目标图中粘贴节点时,将每个节点放置在 &lt;Integer, Node&gt; 映射中(同样从 1 到 N 编号,但映射方向相反,原因很快就会清楚)。

      当您在源图中找到反向链接时,您可以使用第一个映射将该反向链接的“源副本”节点映射到整数 i。接下来,您使用第二个映射查找整数 i 并找到需要创建相同反向链接的“目标副本”节点。

      【讨论】:

      • 我刚刚意识到这与 Gene 上面发布的答案几乎相同,但 NodeNode 映射分解为两个映射。那好吧。 :-)
      【解决方案4】:

      要使克隆高效,请使用两件事:

      • DS 末尾带有 更快的删除和添加。在listqueuestack 中选择
      • DS 具有快速搜索Map 可以快速搜索到,即O(1) amortized。

      算法:

                              To be processed <--> Queue
                                / 
      Not_Cloned_Yet -> Clone it -> Map
            `~~~~~~~~checks~~~~~~~~~~^
      
      
      Root is "Not Cloned yet" and needs to be "To be processed" -- (1)
      Clone it -> Put in Map & Queue  -- (2)
      
      Continue till "To be processed" is not zero. i.e. Queue is not empty. -- (3)
          Traverse and update the list of neighbours  -- (4)
              Neighbours that are "Not cloned yet" needs "Clone it -> Put in Map & Queue"   --(5)
      
      1. 第 2 步和第 5 步基于To be processed --&gt; Queue
      2. Queue -&gt; To be processed 上的第 3 步。
      3. 队列元素是已克隆但未处理(即其邻居列表未更新)的元素。
      4. 邻居可能已克隆,也可能尚未克隆。因此,需要签入地图。

      【讨论】:

        猜你喜欢
        • 2012-05-06
        • 2015-04-17
        • 2020-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多