拓扑搜索和广度优先搜索

时间:2013-02-16 03:16:38

标签: algorithm graph

是否可以使用广度优先搜索逻辑对DAG进行拓扑排序? Cormen的解决方案使用深度优先搜索,但使用BFS会更容易吗?

原因: 在访问具有下一个深度值的节点之前,BFS访问特定深度的所有节点。这自然意味着如果我们做BFS,父母将被列在孩子面前。这不是我们拓扑排序所需要的吗?

4 个答案:

答案 0 :(得分:7)

仅仅BFS仅适用于树木(或树林),因为在(森林)树木中,度数最多为1。 现在,看看这个案例:

B → C → D
      ↗
    A

将队列初始化为A B(其度数为零)的BFS将返回A B D C,这不是拓扑排序的。这就是为什么你必须保持in-degrees计数,并且只挑选计数已降至零的节点。 (*)

顺便说一句,这是你的理由的缺陷' :BFS只保证之前访问过一个父母,而不是所有父母。

编辑 :( *)换句话说,你推回其度数为零的相邻节点(例如,在处理A之后,将跳过D )。因此,您仍在使用队列,并且您刚刚为常规算法添加了过滤步骤。话虽如此,继续称之为BFS是值得怀疑的。

答案 1 :(得分:5)

有可能,甚至维基百科describes an algorithm based on BFS

基本上,您使用一个队列,在该队列中插入所有没有传入边的节点。然后,当您提取节点时,将删除其所有传出边,并插入可从其中到达的没有其他传入边的节点。

答案 2 :(得分:3)

在BFS中,您实际行走的所有边缘都将以正确的方向结束。但是,如果按BFS顺序布置图形,那么你不走的所有边缘(在相同深度的节点之间,或者从较深节点返回到早期节点的边缘)将最终走错路。

是的,你真的需要DFS才能做到。

答案 3 :(得分:0)

是的,您可以使用 BFS 进行拓扑排序。实际上我记得有一次我的老师告诉我,如果问题可以通过 BFS 来解决,那么永远不要选择通过 DFS 来解决。由于 BFS 的逻辑比 DFS 更简单,因此大多数时候您总是希望直接解决问题。

正如YvesgereY和IVlad所提到的,你需要从 indegree 0 的节点开始,这意味着没有其他节点指向它们。请务必先将这些节点添加到结果中。您可以使用HashMap映射每个节点的indegree,以及一个在BFS中常见的队列,以帮助您进行遍历。当您从队列中轮询节点时,其邻居的indegree需要减少1,这就像从图中删除节点并删除节点与其邻居之间的边缘。每次遇到具有0 indegree的节点时,将它们提供给队列以便稍后检查它们的邻居并将它们添加到结果中。

public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {

    ArrayList<DirectedGraphNode> result = new ArrayList<>();
    if (graph == null || graph.size() == 0) {
        return result;
    }
    Map<DirectedGraphNode, Integer> indegree = new HashMap<DirectedGraphNode, Integer>();
    Queue<DirectedGraphNode> queue = new LinkedList<DirectedGraphNode>();

    //mapping node to its indegree to the HashMap, however these nodes
    //have to be directed to by one other node, nodes whose indegree == 0
    //would not be mapped.
    for (DirectedGraphNode DAGNode : graph){
        for (DirectedGraphNode nei : DAGNode.neighbors){
            if(indegree.containsKey(nei)){
                indegree.put(nei, indegree.get(nei) + 1);
            } else {
                indegree.put(nei, 1);
            }
        }
    }


    //find all nodes with indegree == 0. They should be at starting positon in the result
    for (DirectedGraphNode GraphNode : graph) {
        if (!indegree.containsKey(GraphNode)){
            queue.offer(GraphNode);
            result.add(GraphNode);
        }
    }


    //everytime we poll out a node from the queue, it means we delete it from the 
    //graph, we will minus its neighbors indegree by one, this is the same meaning 
    //as we delete the edge from the node to its neighbors.
    while (!queue.isEmpty()) {
        DirectedGraphNode temp = queue.poll();
        for (DirectedGraphNode neighbor : temp.neighbors){
            indegree.put(neighbor, indegree.get(neighbor) - 1);
            if (indegree.get(neighbor) == 0){
                result.add(neighbor);
                queue.offer(neighbor);
            }
        }
    }
    return result;
}
相关问题