简体   繁体   English

使用HashMap进行广度优先搜索 <Vertex, List<Vertex> &gt;

[英]Breadth First Search using HashMap<Vertex, List<Vertex>>

I am trying to perform a breadth first search on a large graph. 我正在尝试在大图上执行广度优先搜索。 I have a list of the vertex's with each of its neighbors. 我有一个与每个邻居相邻的顶点的列表。 I have put the data into a hashmap with the Key being the Vertex and the Value being a List of Vertex that neighbor the Key. 我已将数据放入哈希图中,其中键为顶点,值为与键相邻的顶点列表。 I have tried the following but the second "For Loop" is running indefinitely because of the way I am using the Key/Value pairs to loop. 我已经尝试了以下方法,但是由于我使用“键/值”对进行循环的方式,第二个“ For循环”将无限期运行。 But I can't think of another way to loop properly and hit each node. 但是我想不出另一种方法来正确循环并命中每个节点。

public static void BFS(HashMap<Vertex, List<Vertex>> map) {
        Queue<Vertex> myQ = new LinkedList<Vertex>();
        for(HashMap.Entry<Vertex, List<Vertex>> entry : map.entrySet()) {
            if(entry.getKey().getCount() == 0){
                count++;
                entry.getKey().setCount(count);
                myQ.add(entry.getKey());
                while(!myQ.isEmpty()) {
                    for(Vertex neighbor : entry.getValue()){
                        if(neighbor.getCount() == 0) {
                            count++;
                            neighbor.setCount(count);
                            myQ.add(neighbor);
                        }
                    }
                    myQ.remove(entry.getKey());
                }                   
            }       
        }
    }

the count attribute is used to track if a Vertex has already been visited. count属性用于跟踪是否已访问顶点。

Any help would be appreciated, just looking for a new way of thinking about how to loop through the HashMap. 任何帮助将不胜感激,只需要寻找一种新的方式思考如何遍历HashMap。 Or if I am doing something completely wrong :) 或者,如果我做的事情完全错误:)

If I understand your question and sample code then all you are trying to do is iterate through all the map's values without visiting a vertex more than once. 如果我理解您的问题和示例代码,那么您要做的就是遍历所有地图的值,而不必多次访问顶点。 If so then you can do the following with Java 8: 如果是这样,那么您可以使用Java 8执行以下操作:

map.values().stream().flatMap(List::stream).distinct()
    .forEach(vertex -> {...});

If, however, you want to start from a root node and perform a breadth-first search (which is the normal mechanism) then it's a bit more complicated: 但是,如果您想从根节点开始并执行广度优先搜索(这是正常机制),那么它会更复杂一些:

List<Vertex> completedList = new ArrayList<>();
for (List<Vertex> searchList = Arrays.toList(root);
    !searchList.isEmpty();
    searchList = searchList.stream().map(map::get).flatMap(List::steam)
        .filter(v -> !completedList.contains(v))
        .collect(Collectors.toList())) {
    searchList.forEach(vertex -> {...});
    completedList.addAll(searchList);
}

Assuming a Vertex root to start your search, you code could be something like: 假设Vertex根开始搜索,您的代码可能类似于:

public static void BFS(Vertex root, HashMap<Vertex, List<Vertex>> map) {
    Deque<Vertex> myQ = new LinkedList<Vertex>();
    myQ.add(root);
    while(!myQ.empty()) {
        Vertex current = myQ.getFirst();
        current.visited = true;
        // Or you can store a set of visited vertices somewhere
        List<Vertex> neighbors = map.get(current);
        for (Vertex neighbor : neighbors) {
            if (!neighbor.visited) {
                myQ.addLast(neighbor);
            }
        }
    }
}

Here, I have not really tried this code, so it probably won't even compile as it is, but it should not be difficult to get it to work. 在这里,我还没有真正尝试过这个代码,因此它可能甚至不会按原样进行编译,但要让它工作起来并不困难。 As it is, it should give you a good idea of how the algorithm is supposed to work. 实际上,它应该使您对算法的工作原理有一个很好的了解。

public void BFS( HashMap<Vertex, List<Vertex>> map )
{
    if( map.isEmpty() )
        return;

    /* pick an arbitrary first vertex to start from */
    Vertex start = null;
    for( Vertex temp : map.getKeys() )
    {
         start = temp;
         break;
    }

    /* visit first vertex */
    visit( start );

    /* start recursion */
    BFS( start, map );
}

public void BFS( Vertex start, HashMap<Vertex, List<Vertex>> map )
{
    /* mark the current vertex as visited */
    int count = start.getCount();
    assert count == 0;
    count++;
    start.setCount( count );

    /* visit each unvisited neighboring vertex */
    for( Vertex neighbor : map.get( start ) ) 
    {
        if( neighbor.getCount() != 0 )
            continue;
        visit( neighbor );
    }

    /* recurse into each unvisited neighboring vertex */
    for( Vertex neighbor : map.get( start ) ) 
    {
        if( neighbor.getCount() != 0 )
            continue;
        BFS( neighbor, map );
    }
}

But, before you proceed with this, I would strongly recommend that you define a new Graph class, encapsulating the map of vertices, and offering operations that make sense in graph terminology instead of java collections terminology. 但是,在继续进行此操作之前,我强烈建议您定义一个新的Graph类,封装顶点图,并提供在图形术语而非Java集合术语中有意义的操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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