Alguém poderia me ajudar nessa atividade sobre busca em largura em um grafo?

atividade grafo
package Grafos;

import java.io.;
import java.util.
;

class Graph {
private int V;
private LinkedList adj[];

Graph(int v) {
	V = v;
	adj = new LinkedList[v];
	for (int i = 0; i < v; ++i)
		adj[i] = new LinkedList();
}


void addEdge(int v, int w) {
	adj[v].add(w);
}


void BFS(int s) {
	
	boolean visited[] = new boolean[V];

	
	LinkedList<Integer> queue = new LinkedList<Integer>();

	
	visited[s] = true;
	queue.add(s);

	while (queue.size() != 0) {
		
		s = queue.poll();
		System.out.print(s + " ");

	
		Iterator<Integer> i = adj[s].listIterator();
		while (i.hasNext()) {
			int n = i.next();
			if (!visited[n]) {
				visited[n] = true;
				queue.add(n);
			}
		}
	}
}


public static void main(String args[]) {
	Graph g = new Graph(4);

	g.addEdge(0, 1);
	g.addEdge(0, 2);
	g.addEdge(1, 2);
	g.addEdge(2, 0);
	g.addEdge(2, 3);
	g.addEdge(3, 3);

	System.out.println("A seguir está a primeira travessia em largura " + "(starting from vertex 2)");

	g.BFS(2);
}

}

O grafo da imagem possui 6 vértices porque você criou só com 4?

Os vértices do grafo da imagem são representados por letras, por que você está usando números?

Já tentei usar letras mas não funciona

O grafo da imagem possui 6 vértices porque você criou só com 4? Ah sim, não tinha observado esse detalhe

Você copiou essa classe de alguém?
Porque implementou ela esperando receber os vértices na forma de int?

foi a forma que eu conseguir declarando int na variável V, tambem tentei usar uma string mesmo assim não vai

Pq grafos “didáticos” não crescem. A ideia é criar com tamanho fixo mesmo e focar nos algoritmos.

Tá aí:

import java.util.LinkedList;
import java.util.Queue;

/**
 *
 * @author David
 */
public class Graph {

    private int V;
    private LinkedList<Integer> adj[];

    Graph( int v ) {
        V = v;
        adj = new LinkedList[v];
        for ( int i = 0; i < v; ++i ) {
            adj[i] = new LinkedList();
        }
    }

    void addEdge( int v, int w ) {
        adj[v].add( w );
        adj[w].add( v );
    }

    void BFS( int s ) {

        boolean visited[] = new boolean[V];

        Queue<Integer> queue = new LinkedList<>();

        visited[s] = true;
        queue.add( s );

        while ( !queue.isEmpty() ) {

            s = queue.poll();
            System.out.println( s + " " );

            for ( int n : adj[s] ) {
                if ( !visited[n] ) {
                    visited[n] = true;
                    queue.add( n );
                }
            }
            
        }
    }

    public static void main( String args[] ) {
        
        Graph g = new Graph( 4 );

        g.addEdge( 0, 1 );
        g.addEdge( 0, 2 );
        g.addEdge( 1, 2 );
        g.addEdge( 2, 3 );

        System.out.println( "A seguir está a primeira travessia em largura " + "(starting from vertex 2)" );

        g.BFS( 2 );
        
    }
    
}

Ao adicionar uma aresta em um grafo não dirigido, vc precisa fazer a ida e a volta. Veja o que mudou no método addEdge. Se já existe ida e volta, a chamada g.addEdge(2, 0); insere um “anomalia” no seu grafo, chamada de aresta paralela. Ela pode existir, não há problema, só vai fazer seu algoritmo demorar um pouco mais. Outra anomalia do seu exemplo, que tbm pode existir é o laço/loop criado na chamada g.addEdge(3, 3); que não terá efeito algum sobre a busca em largura, visto que o vértice atual será marcado como visitado assim que for alcançado. Na ordem em que estão feitas as inserções das arestas no meu exemplo, removendo as duas chamadas acima, você terá o array adj populado da seguinte forma:

adj[0] = { 2, 1 }
adj[1] = { 2, 0 }
adj[2] = { 3, 1, 0 }
adj[3] = { 2 }

Os valores entre chaves representam as listas usadas. Lembre-se que as inserções são feitas na cauda/rabo/fim da lista e são feitas nas duas direções.

Você inicia a busca pelo vértice 2, então terá algo assim durante a execução:

// início
visited = F | F | F | F  (F = false, T = true)
          0   1   2   3

queue = {}

// inserção da fonte na fila e marcação de visitado
visited = F | F | T | F
          0   1   2   3

queue = { 2 }

// a fila está vazia? não!
s = 2
queue = {}

adjacentes de 2:
    3: visitado? não!
       visited[3] = true;  =>  visited = F | F | T | T
       queue = { 3 }                     0   1   2   3
       
    1: visitado? não!
       visited[1] = true;  =>  visited = F | T | T | T
       queue = { 1, 3 }                  0   1   2   3
       
    0: visitado? não!
       visited[0] = true;  =>  visited = T | T | T | T
       queue = { 0, 1, 3 }               0   1   2   3

// perceba que no seu exemplo, todos os vértices
// já estão visitados e a árvore de busca em largura 
// gerada já está pronta (seu exemplo não a codifica, 
// se quiser eu complemento para vc.

// a ideia da busca em largura é obter essa árvore e
// os custos associados a quantidade de "pulos" que se
// da de um vértice a outro, sendo algo parecido com um
// algoritmo de menor caminho, mas sem pesos nas arestas

// continuando...
// a fila está vazia? não!
s = 3
queue = { 0, 1 }

adjacentes de 3:
    2: visitado? sim!

// a fila está vazia? não!
s = 1
queue = { 0 }

adjacentes de 1:
    2: visitado? sim!
    0: visitado? sim!
    
// a fila está vazia? não!
s = 0
queue = {}

adjacentes de 0:
    2: visitado? sim!
    1: visitado? sim!
    
// a fila está vazia? sim!

Cara, muito obrigado pela ajuda

Só fiquei com uma duvida, esse exemplo que você modificou está completo?

Sim, só que não é armazenada a árvore e as distâncias. Ele mostra na saída os vértices que estão sendo processados no momento que saem da fila. O ideal seria ter algo mais robusto do ponto de vista de utilidade. Veja o terceiro link que te passei. O array edgeTo armazena o caminho da árvore e o array distTo armazena as distâncias da fonte até o vértice em questão. Acho que foi vc que perguntou sobre busca em profundidade há alguns dias atrás não foi? A ideia é a mesma.

Sim foi eu mesmo, ah entendi

Meu questionamento não foi o int no construtor, que determina a quantidade de vértices, mas o motivo de ele usar int para representar os vértices sendo que no desenho eles são representados por letras.

Se ele quisesse representar o grafo do desenho, sua classe Graph seria adaptada para funcionar com char ou String ao invés de int, poderia até fazer algo mais elaborado com uma classe Vertex para servir de container genérico.
Mas enfim, a ideia seria representar o grafo da imagem dessa forma:

Graph g = new Graph( 6 );

g.addEdge( 'a', 'b' );
g.addEdge( 'a', 'f' );
g.addEdge( 'b', 'c' );
g.addEdge( 'b', 'd' );
g.addEdge( 'b', 'f' );
g.addEdge( 'c', 'd' );
g.addEdge( 'c', 'f' );
g.addEdge( 'd', 'e' );
g.addEdge( 'd', 'f' );
g.addEdge( 'e', 'f' );

Um dos motivos, o principal na verdade, é o acesso direto ao índice do array que armazena as listas de adjacências, pq a ideia é ter uma implementação “ótima” de um grafo. É claro, vc poderia fazer um mapeamento char → int, mas se há a necessidade de armazenar rótulos para os vértices a abordagem normal é usar uma tabela de símbolos para associar o vértice (inteiro) com o rótulo.

2 curtidas

“Usar uma tabela de símbolos para associar o vértice (inteiro) com o rótulo” Desse modo poderia usar string ?