Grafo não-direcionado

Boa Tarde!

Estou precisando desenvolver um programa de grafo não-direcionado para um trabalho.
A entrada do dos dados vai ser realizada através da entrada de dados de um arquivo .txt , que vai conter o número de nós, numero de arestas e o nó a partir do qual será executada a busca.
Exemplo:
<numero de nós>

<nó a partir do qual será executada a pesquisa >
<lista de pares de nós conectados>

Exemplo:

8
10
2
1 2
3 4
1 5
2 6
3 6
3 7
4 7
4 8
6 7
7 8

O que fiz até o momento…

import java.util.*;

public class Graph {

  private Map<Integer, Node> nodes;

  public Graph() {
    this.nodes = new HashMap<Integer, Node>();
  }

  public void breadthFirstSearch(int noInicial) {

    // Condições iniciais para o nó de origem
    Node snode = nodes.get(noInicial);
    snode.setColor(Node.Color.GRAY);
    snode.setDistance(0);

    Queue<Integer> q = new LinkedList<Integer>();
    q.add(noInicial);

    while (!q.isEmpty()) {
      Node unode = nodes.get(q.poll());

      for (int v : unode.getEdges()) {
        Node vnode = nodes.get(v);
        if (vnode.getColor() == Node.Color.WHITE) {
          vnode.setColor(Node.Color.GRAY);
          vnode.setDistance(unode.getDistance() + 1);
          vnode.setParent(unode.getId());
          q.add(v);
        }
      }
      unode.setColor(Node.Color.BLACK);
    }
  }

  public void addNode(int id, int[] edges) {

    // A couple lines of hacky code to transform our
    // input integer arrays (which are most comprehensible
    // write out in our main method) into List<Integer>
    List<Integer> list = new ArrayList<Integer>();
    for (int edge : edges)
      list.add(edge);

    Node node = new Node(id);
    node.setEdges(list);
    nodes.put(id, node);
  }
  
  public void print() {
    for (int v : nodes.keySet()) {
      Node vnode = nodes.get(v);
      System.out.printf("nó = %2d distância = %2d \n", vnode.getId(), vnode.getDistance());
    }
  }

  public static void main(String[] args) {

    Graph graph = new Graph();
    graph.addNode(1, new int[] { 2, 5 });
    graph.addNode(2, new int[] { 1, 6 });
    graph.addNode(3, new int[] { 4, 6, 7 });
    graph.addNode(4, new int[] { 3, 7, 8 });
    graph.addNode(5, new int[] { 1 });
    graph.addNode(6, new int[] { 2, 3, 7 });
    graph.addNode(7, new int[] { 3, 4, 6, 8 });
    graph.addNode(8, new int[] { 4, 7 });

    graph.breadthFirstSearch(2);
    graph.print();
  }

}

Só uma dica.
Se você achou esse código na Internet, o seu professor também o achará, e assim, a chance de ter o trabalho anulado por plágio é grande…
Mas… vai em frente né. Boa sorte

marcioberlitz
Complementando o que o ruivo disse, se o código para isso tenha que ser seu (o que fica difícil, já que a busca em largura usada nesse caso é um algoritmo bem conhecido), acho que vale a pena informar seu professor que o código não é seu e de onde você copiou, além das alterações que fez. Um passo importante você já deu: está tentando entender o código.

Sobre o código, está faltando você mostrar a classe Node.

while (!q.isEmpty()) { // enquanto a lista "q" não estiver vazia Node unode = nodes.get(q.poll()); // unode recebe um elemento do vetor nodes

q.poll() => remove o item que é o primeiro da lista;
nodes.get() => pega o elemento do Map chamado nodes que corresponde ao objeto node passado por prâmetro

Note que o for logo abaixo faz parte desse while, e que ele é crucial para detectar a sequência de nós visitados.

[quote=marcioberlitz]Ali na Void addNode, já tem um comentário em inglês, mas não consegui entender extamente o que ele faz ali.
Alguém saberia me dizer?[/quote]

Você não entendeu o objetivo do método (adicionar um nó ao grafo), ou não entendeu o código interno dele?

Abraço.

Pois é, mas o professor sempre fala em aula, que o objetivo da cadeira não é de que a gente aprende a programar e sim entenda a complexidade do algoritmo. A disciplina se chama “Complexidade de Algoritmos”.
Tanto que fizemos programas de ordenação, lista encadeada, hashtable, arvore binaria e tal, e ele autorizou a usarmos programas feitos, nós só tivemos que fazer algumas modificações que ele solicitou, como colocar contador de tempo para verificar os tempos dos softwares, fazer comparações entre eles e tal.Ex: comparar bubble sort com selection sort, arvore binaria com red black tree.

Nós só teriamos que utilizar aquele algoritmo de pesquisa em largura do livro do Cormen, vcs conhecem?

[quote=TerraSkilll]marcioberlitz
Complementando o que o ruivo disse, se o código para isso tenha que ser seu (o que fica difícil, já que a busca em largura usada nesse caso é um algoritmo bem conhecido), acho que vale a pena informar seu professor que o código não é seu e de onde você copiou, além das alterações que fez. Um passo importante você já deu: está tentando entender o código.

Sobre o código, está faltando você mostrar a classe Node.

while (!q.isEmpty()) { // enquanto a lista "q" não estiver vazia Node unode = nodes.get(q.poll()); // unode recebe um elemento do vetor nodes

q.poll() => remove o item que é o primeiro da lista;
nodes.get() => pega o elemento do Map chamado nodes que corresponde ao objeto node passado por prâmetro

Note que o for logo abaixo faz parte desse while, e que ele é crucial para detectar a sequência de nós visitados.

[quote=marcioberlitz]Ali na Void addNode, já tem um comentário em inglês, mas não consegui entender extamente o que ele faz ali.
Alguém saberia me dizer?[/quote]

Você não entendeu o objetivo do método (adicionar um nó ao grafo), ou não entendeu o código interno dele?

Abraço.[/quote]

Não entendi o código mesmo, como disse eu não sou bom programador, fiz as disciplinas de programação a varios semestres e atualmente não esou trabalhando na area.

[code]public void addNode(int id, int[] edges) {

List<Integer> list = new ArrayList<Integer>();
for (int edge : edges)
  list.add(edge);

Node node = new Node(id);
node.setEdges(list);
nodes.put(id, node);    

}[/code]

como funciona aquele for ali, edge quer dizer borda certo?
de borda até bordas ele adiciona na lista?

graph.addNode(4, new int[] { 3, 7, 8 });

Por exemplo aqui que conecto o ó 4 com 3,7 e 8.
É aquele for que lê de 3 até o 8 e depois adiciona na lista?

[quote=TerraSkilll]marcioberlitz

Sobre o código, está faltando você mostrar a classe Node.

while (!q.isEmpty()) { // enquanto a lista "q" não estiver vazia Node unode = nodes.get(q.poll()); // unode recebe um elemento do vetor nodes

Abraço.[/quote]

ah esqueci, segue a classe node

import java.util.*;

public class Node {
  
  public static enum Color {WHITE, GRAY, BLACK};
  
  private final int id;
  private int parent = Integer.MAX_VALUE;
  private int distance = Integer.MAX_VALUE;
  private List<Integer> edges = null;
  private Color color = Color.WHITE;
  
  public Node(int id) {
    this.id = id;
  }
  
  public int getId(){
    return this.id;
  }
  
  public int getParent() {
    return this.parent;
  }
  
  public void setParent(int parent) {
    this.parent = parent;
  }
  
  public int getDistance(){
    return this.distance;
  }
  
  public void setDistance(int distance) {
    this.distance = distance;
  }
  
  public Color getColor(){
    return this.color;
  }
  
  public void setColor(Color color){
    this.color = color;
  }
  
  public List<Integer> getEdges(){
    return this.edges;
  }
  
  public void setEdges(List<Integer> vertices) {
    this.edges = vertices;
  }  

}

marcioberlitz

Que curso você faz?

Complexidade de Algoritmos é bastante interessante (embora cansativa e um tanto teórica). E essa abordagem do seu professor parece ajudar bastante a compreensão.

Se conheço: http://img10.imageshack.us/img10/2313/algoritmos.gif. Causou pesadelos em algumas pessoas que conheço.

[quote]como funciona aquele for ali, edge quer dizer borda certo?
de borda até bordas ele adiciona na lista? [/quote]
Edge, no contexto de grafos, quer dizer aresta. Cuidado ao traduzir os termos, tem que se preocupar com o contexto.

[quote]Por exemplo aqui que conecto o ó 4 com 3,7 e 8.
É aquele for que lê de 3 até o 8 e depois adiciona na lista? [/quote]

Simplificando a ideia, é isso mesmo. O método addNode adiciona ao grafo um vértice (4, nesse caso) e a matriz que é passada (3, 7, 8 ) indica a quais vértices esse novo vértice está conectado. Nesse modelo, um grafo está representado por uma coleção de vértices (Hashmap() Node, na classe Graph) e as arestas são indicadas por uma lista de inteiros (private List edges = null;, na classe Node).

Abraço.

[quote=TerraSkilll]marcioberlitz

Que curso você faz?

Complexidade de Algoritmos é bastante interessante (embora cansativa e um tanto teórica). E essa abordagem do seu professor parece ajudar bastante a compreensão.

Se conheço: http://img10.imageshack.us/img10/2313/algoritmos.gif. Causou pesadelos em algumas pessoas que conheço.

[quote]como funciona aquele for ali, edge quer dizer borda certo?
de borda até bordas ele adiciona na lista? [/quote]
Edge, no contexto de grafos, quer dizer aresta. Cuidado ao traduzir os termos, tem que se preocupar com o contexto.

[quote]Por exemplo aqui que conecto o ó 4 com 3,7 e 8.
É aquele for que lê de 3 até o 8 e depois adiciona na lista? [/quote]

Simplificando a ideia, é isso mesmo. O método addNode adiciona ao grafo um vértice (4, nesse caso) e a matriz que é passada (3, 7, 8 ) indica a quais vértices esse novo vértice está conectado. Nesse modelo, um grafo está representado por uma coleção de vértices (Hashmap() Node, na classe Graph) e as arestas são indicadas por uma lista de inteiros (private List edges = null;, na classe Node).

Abraço.[/quote]

Eu faço Ciencias da Computação, eu sei que deveria saber programar pelo curso que faço, mas como não trabalho na area de programação, e já fiz a vários anos cadeiras de programação(estou na faculdade desde 2004) estou com muita dificuldade.
Mas com sua ajuda estou conseguindo entender as poucos o código. Estou colocando comentários em várias linhas, depois que eu terminar, vou postar dinovo pra vc dar uma analizada, pode ser?
E me diz uma coisa, esse algoritmo que estou utilizando, ele é muito diferente do utilizado do livro do Cormen?
Este é mais fácil de ser implementado?

Obrigado pela ajuda até o momento!

A entrada dos dados vai ser através de um arquivo txt, exemplo:
1 2
3 4
1 5
2 6
3 6
3 7
4 7
4 8
6 7
7 8

Nó 1 se conecta com 2 e o 2 com 1, e assim seguindo.

Fiz isso aqui até o momento:

[code] Hashtable<Integer, List> table= new Hashtable<Integer, List>();

  try {  
      File file = new File("C://dados.txt");  
      FileInputStream in = new FileInputStream( file );  
      Scanner scanner = new Scanner(in);
      
      while (scanner.hasNext()) {  
          String primeiro = scanner.next();
          String segundo = scanner.next();
          for(int i = 0; i < 1; i ++){ 
              
              int key = Integer.parseInt(primeiro);                  
              
              if (table.get(key)==null){ //Então verifica se já existe na hashtable a lista do número,senão existe cria uma nova lista desse número     
                  table.put(key, new ArrayList<Integer>()); 
              }
              table.get(key).add(Integer.parseInt(segundo)); //adiciona o número em sua determinada lista                  
          }
     }[/code]

Minha saida esta assim por enquanto:

{7=[8], 6=[7], 4=[7, 8], 3=[4, 6, 7], 2=[6], 1=[2, 5]}

To quase lá, mas ainda esta faltando alguma coisa. Na lista 1 ele adicionou o número 2, conforme a primeira ligação do arquivo txt, mas preciso adicionar o número 1 na lista 2 também, mas não estou conseguindo. Alguém sabe como posso fazer isso??

Bah, consegui fazer até, não sei se foi da melhor maneira, mas funcionou…coloquei mais um for ali…

[code]
Hashtable<Integer, List> table= new Hashtable<Integer, List>();
try {
File file = new File(“C://dados.txt”);
FileInputStream in = new FileInputStream( file );
Scanner scanner = new Scanner(in);

      while (scanner.hasNext()) {  
          String primeiro = scanner.next();
          String segundo = scanner.next();
          for(int i = 0; i < 1; i ++){
           
              int key = Integer.parseInt(primeiro);                  
              
              if (table.get(key)==null){ //Então verifica se já existe na hashtable a lista do número,senão existe cria uma nova lista desse número     
                  table.put(key, new ArrayList<Integer>()); 
              }
              table.get(key).add(Integer.parseInt(segundo)); //adiciona o número em sua determinada lista                  
          }
          
          for(int i = 0; i < 1; i ++){           	 
              
              int key = Integer.parseInt(segundo);                  
              
              if (table.get(key)==null){ //Então verifica se já existe na hashtable a lista do número,senão existe cria uma nova lista desse número     
                  table.put(key, new ArrayList<Integer>()); 
              }
              table.get(key).add(Integer.parseInt(primeiro)); //adiciona o número em sua determinada lista                  
          }              
          
     }[/code]

Saida:
{8=[4, 7], 7=[3, 4, 6, 8], 6=[2, 3, 7], 5=[1], 4=[3, 7, 8], 3=[4, 6, 7], 2=[1, 6], 1=[2, 5]}

Assim ta ok.
Agora estou com dificuldade para adicionar essas informações no grafo:

Maneira manual era assim:

Graph graph = new Graph(); graph.addNode(1, new int[] { 2, 5 }); graph.addNode(2, new int[] { 1, 6 }); graph.addNode(3, new int[] { 4, 6, 7 }); graph.addNode(4, new int[] { 3, 7, 8 }); graph.addNode(5, new int[] { 1 }); graph.addNode(6, new int[] { 2, 3, 7 }); graph.addNode(7, new int[] { 3, 4, 6, 8 }); graph.addNode(8, new int[] { 4, 7 });

Como faço para ler os valores dentro da HashTable e jogar eles no grafo?
Eu tinha pensado em algo assim:

Graph graph = new Graph();
          
          for(int i = 1; i < 9; i ++){        	  
          List<Integer> list = table.get(i);
          
          for (Integer n:list){ 
          graph.addNode(i, new int[] { n });	  
          		}  
          }          
          graph.print();
          graph.pesquisaLargura(2);

Ele esta gerando a seguinte saida:

nó = 1 distância = 2147483647
nó = 2 distância = 0
nó = 3 distância = 2147483647
nó = 4 distância = 2147483647
nó = 5 distância = 2147483647
nó = 6 distância = 1
nó = 7 distância = 2
nó = 8 distância = 3

Mas deveria sair assim:

nó = 1 distância = 1
nó = 2 distância = 0
nó = 3 distância = 2
nó = 4 distância = 3
nó = 5 distância = 2
nó = 6 distância = 1
nó = 7 distância = 2
nó = 8 distância = 3

Estranho que alguns estao certos…

Coloquei um print ali pra ver como que esta sendo inserido os dados…esta praticamente certo.
Só que ele esta inserindo desta maneira:

graph.addNode(1, new int[] { 2 });
graph.addNode(1, new int[] { 5 });
…até o final

mas ele deveria inserir assim

graph.addNode(1, new int[] { 2, 5 });

Deve ser por isso que ele não calcula a distancia corretamente, vou tentar descobrir aqui, mas se alguém tiver alguma dica.

[quote=marcioberlitz]Coloquei um print ali pra ver como que esta sendo inserido os dados…esta praticamente certo.
Só que ele esta inserindo desta maneira:

graph.addNode(1, new int[] { 2 });
graph.addNode(1, new int[] { 5 });
…até o final

mas ele deveria inserir assim

graph.addNode(1, new int[] { 2, 5 });

Deve ser por isso que ele não calcula a distancia corretamente, vou tentar descobrir aqui, mas se alguém tiver alguma dica.[/quote]

Por incrivel que parece consegui fazer, ficou assim:

Graph graph = new Graph();
          
          for(int i = 1; i < Integer.parseInt(numNos)+1; i ++){        	  
          List<Integer> list = table.get(i);
          List<Integer> lista = table.get(i);
          System.out.println("Lista:"+i+lista);          
          
          for (Integer n:list){         	  
          graph.addNode(i, new List[] { lista });
//        System.out.println("i= " +i);
//        System.out.println("n= " +n);
          		}  
          }
          graph.pesquisaLargura(2);
          graph.print();
//        System.out.println(table); 

Não tem problema do meu for iniciar com 1 né?
Não sei aonde li a respeito que em java deveria iniciar sempre em ZERO, no meu caso se inicio em ZERO, ele faz de 0 à 7, mas tenho que fazer de 1 à 8.