Grafo não-direcionado

12 respostas
M

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

12 Respostas

M

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();
  }

}
ruivo

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

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.

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?

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.

M

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?

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

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?

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.

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.

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);    
  }

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?

M

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.

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;
  }  

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

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

Edge, no contexto de grafos, quer dizer aresta. Cuidado ao traduzir os termos, tem que se preocupar com o contexto.

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?

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.

M

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.

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

Edge, no contexto de grafos, quer dizer aresta. Cuidado ao traduzir os termos, tem que se preocupar com o contexto.

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?

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.

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!

M

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:
Hashtable<Integer, List<Integer>> table= new Hashtable<Integer, List<Integer>>();
	  
	  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                  
              }
         }

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

M

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

Hashtable<Integer, List<Integer>> table= new Hashtable<Integer, List<Integer>>();
          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                  
              }              
              
         }

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 = [telefone removido]
nó = 2 distância = 0
nó = 3 distância = [telefone removido]
nó = 4 distância = [telefone removido]
nó = 5 distância = [telefone removido]
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...

M

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.

M

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.

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.

Criado 15 de novembro de 2011
Ultima resposta 17 de nov. de 2011
Respostas 12
Participantes 3