Check if the graph is connected

Can anyone tell me how can I implement a method that checks me if an undirected graph is connected, and if it is not, return its connected components?

public void connectComps(){
    ArrayList<LinkedList<Estacao>> css = new ArrayList<>();
    Map<Estacao, Boolean> visited = new HashMap<>();
    for(Estacao est : mapaEstacoes.vertices()){
        visited.put(est, false);
    }
    for(Estacao v : mapaEstacoes.vertices()){
        if(visited.getOrDefault(v, Boolean.FALSE)){
            LinkedList<Estacao> aux = GraphAlgorithms.BreadthFirstSearch(mapaEstacoes, v);
            css.add(aux);
        }
    }
}
 4
Author: Jefferson Quesado, 2018-11-17

1 answers

Since doubt is about non-directed graphs, I am using this as a premise in my entire answer. Everything I write goes for non-directed graphs, unless you find some external reference that demonstrates otherwise. I will not take care here to explain what is valid for directed graphs.

Let's start by defining what is a related component? This will serve as the basis for eventual code and also for by a denominator common to those who get here.

A connected component consists of a vertex and all other vertices it can reach. How is this done? Well, we can see this recursively:

    Let
  1. be the vertex V a vertex of interest; by definition, V is within the scope of V, so it belongs to a related component
  2. all edges containing V and pointing to other vertices Ui increase the range of V, so all Ui they are also within the range of V
  3. coming out of each Ui through its vertices, we come to Tij, which are in the range of Ui and therefore in the range of V

I would particularly do the navigation to determine the range of a vertex through a depth search, not a width search. Why? Because with an in-depth search I have a smaller memory peak in most cases (the opposite can happen in sparse graphs, where the deep search can take up more memory) and because it is easier to implement.

How would I do this search? Well, it depends a lot on how your graph is structured. I really like the adjacency array, but it doesn't seem to be your case. I will pretend that the object mapaEstacoes has a method List<Estacao> vizinhos(Estacao e) that returns all the neighbors of e. I tried to think of some way to make my code the most similar to what you posted, however, as yours isn't recursive and I don't I understood the use nor need of the variable css, I could not.

Basically, I'm going to fetch all the related components of a graph. I will map these connected components into sequential identifiers and map each station to a connected component. Therefore, I will have a Map<Estacao, Integer> that will identify, for that station, what its connected component is.

The search will start by passing a vertex (representing an unpublished connected component) and the identifier of the component related. As I reach new vertices, they surely follow one of these two properties: (a) they are already in the related component in question, (b) they have not yet been visited. I will indicate that a vertex has not been visited yet when the query to the vertex map for the identifier of the connected component results in null.

public static Map<Estacao, Integer> buscarComponentesConexos(GrafoMisterioso mapaEstacoes) {
    Map<Estacao, Integer> relacaoComponentesConexos = new HashMap<>();
    int idComponenteConexoInedito = 0;

    for (Estacao v: mapaEstacoes.vertices()) {
        if (relacaoComponentesConexos.get(v) == null) {
            determinaComponenteConexo(v, idComponenteConexoInedito, mapaEstacoes, relacaoComponentesConexos);
            idComponenteConexoInedito++;
        }
    }
    return relacaoComponentesConexos;
}

private static void determinaComponenteConexo(Estacao v, int idComponenteConexo, GrafoMisterioso mapaEstacoes, Map<Estacao, Integer> relacaoComponentesConexos) {
    // se eu cheguei aqui, então devo marcar o vértice passado como pertencente ao componente conexo
    relacaoComponentesConexos.put(v, idComponenteConexo);

    // percorre os vizinhos...
    for (Estacao u: mapaEstacoes.vizinhos(v)) {
        // se o vizinho u ainda não foi visitado, visite-o
        if (relacaoComponentesConexos.get(u) == null) {
            determinaComponenteConexo(u, idComponenteConexo, mapaEstacoes, relacaoComponentesConexos);
        }
    }
}

With this, from a graph, we can determine for all its points which are its related components. No exactly the related components, but almost...

A graph is said to be connected if it contains only a single connected component. How can I find out? Well, let's use a stream to check if there is any index greater than zero?

Map<Estacao, Integer> relacaoComponenteConexo = buscarComponentesConexos(mapaEstacoes);
OptionalInt qualquerOutro = relacaoComponenteConexo.values().stream().mapToInt(Integer::intValue).filter(v -> v > 0).findAny(); // estou considerando que o sequencial 0 sempre é usado para o primeiro componente conexo
boolean grafoConexo = !qualquerOutro.isPresent();

What if it is necessary to search for each related component? Well, in that case, we need to reverse the mapping. Now, should I map from an index to a list of vertices:

Map<Estacao, Integer> relacaoComponenteConexo = buscarComponentesConexos(mapaEstacoes);
Map<Integer, List<Estacao>> = relacaoComponenteConexo.entrySet().stream()
  .collect(
            Collectors.groupingBy(es -> es.getValue(),
              Collectors.mapping(Entry::getKey, Collectors.toList())));
 6
Author: Jefferson Quesado, 2019-01-10 13:54:43