简体   繁体   中英

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. 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.

Any help would be appreciated, just looking for a new way of thinking about how to loop through the 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:

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:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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