English version at the following link:
enprogramminghome.blogspot.com
Olá pessoal,
Em link está um uma classe que programei que possui um único método search(type::TypeSearchEnum, v:int, cost:Graph<Double,Double>):SearchInfo
Vamos discutir a O.O deste método:
Esse método foi projetado para que diferentes tipos de buscas pudessem ser realizadas. A enumeração TypeSearchEnum tem somente o tipo "DIJKSTRA", pois somente programei
esse tipo de busca. Posteriormente, podemos inserir "BFS", "DFS","KRUSKAL",...
Se "TypeSearchEnum" é "DIJKSTRA" é chamado o método privado
-dijkstra(v:int, cost:Graph<Double,Double>):SearchInfo
Obviamente, este último método faz busca de Dijkstra em um grafo definido pela interface Graph&lK,V> (K = V = Double). Porque um objeto Graph<K,V>?
Eu poderia ter criado uma assinatura para cada tipo de grafo ex: "double[][] custos",
"LinkedList<LinkedList<Double>> custos", "ArrayList<ArrayList<Double>> custos", "ArrayList<LinkedList<Double>> custos"...
É possível pensar em uma quantidade enorme de assinaturas, o que implica em multiplicação de código. Agora, imagine que todos esses exemplos de grafos acima implementem uma interface "Graph<K,V>" que contém métodos de acesso apropriados a estrutura de dados. Assim, criando uma única assinatura podemos lidar com esse problema!!! (Polimorfismo pela interface)
Com essa aplicação percebe-se que nós saímos daquela idéia simplista de que uma interface é apenas um contrato. O que vimos acima é a vantagem das interfaces, um
polimorfismo inigualável.
O método acima retorna um objeto SearchInfo (explicarei esse objeto daqui a pouco) que contém os resultados da busca. Quais são esses resultados?
Evidentemente, cada vértice é representado por um inteiro. O resultado de uma busca a partir de um vertice "v" são os menores caminhos dele para TODOS os demais vértices. Um menor caminho não é baseado no número de vértices e sim na menor distância, então, é interessante que também sejam as menores distâncias. E são essas informações que SearchInfo armazena. Esta classe disponibiliza dois métodos públicos para consulta.
getPathFrom(vertex:int):LinkedList{Integer}
Este método retorna o menor caminho do vértice "v" para um vértice "vertex" do grafo. Uma linkedlist é usada devido as diferenças que podem existir no número de elementos em um caminho e também porque os elementos são inseridos por addFirst(e:E) (esse método executa em O(1)).
getPathFrom(vertex:int):double
Este método retorna a menor distância do vértice "v" para um vértice "vertex" do grafo.
A classe SearchInfo é interna a SearchGraphAlgorithms, pública e com construtor privado. Isso foi pensado da seguinte maneira:
Essa classe deveria conter um método que contruisse os caminhos a partir de um vetor de vértices anteriores gerado pelo método de dijkstra. Mas as pessoas não devem acessar esse método externamente, então, ele deveria ser privado. Contudo, a classe SearchGraphAlgorithms deve ser capaz de usar esse método de construção de caminhos, assim, a classe SearchInfo deve ser interna a SearchGraphAlgorithms.
SearchInfo deve ser pública para que código externo seja capaz de acessar os resultados da busca, contudo, o contrutor é criado a partir de uma vetor de menores distâncias gerado pelo método "dijkstra", então, o construtor deve ser privado a código externo e vísivel a SearchGraphAlgorithms, o que é possível pois SearchInfo é interno.
A interface Graph contém somente dois métodos:
+ get(i:int, j:int):V
+ size():int
Como aplicação, criei uma classe MatGraph
Ex:
8
0 * * * * * * *
30 0 * * * * * *
100 80 0 * * * * *
* * 120 0 * * * *
* * * 150 0 25 * *
* * * 100 * 0 90 140
* * * * * * 0 100
170 * * * * * * 0
A primeira linha deve conter o número de vértices. As demais linhas contêm as distâncias das adjacências. Quando não existir conexão o símbolo "*" deve ser inserido.
Na Classe Main está a aplicação desses códigos.
A numeração dos vértices começam a partir do zero.
Espero que tenham gostado!
Considerações finais:
Seja correto, caso você copie esse código no seu trabalho/projeto não deixe de indicar a minha autoria. Lembre-se que esse post é muito fácil de achar na internet e possui uma Orientação a Objetos um tanto peculiar, não seja uma pessoa tola.
7 comentários:
A eficiência do Algoritmo de Dijkstra eh notável, mas o que chamou a minha atenção foi o uso da interface. Lembro de ter visto isso no curso do IME.
Ola, percebi que a sua implementação esta furada:
A partir do vertice 4:
Menor Caminho para o
Vertice 0 [4, 5, 7, 0]
Vertice 1 [4, 5, 3, 2, 1]
Vertice 2 [4, 5, 3, 2]
Vertice 3 [4, 5, 3]
Vertice 4 [4]
Vertice 5 [4, 5]
Vertice 6 [4, 5, 6]
Vertice 7 [4, 5, 7]
Menor Distancia para o
Vertice 0 335.0
Vertice 1 325.0
Vertice 2 245.0
Vertice 3 125.0
Vertice 4 0.0
Vertice 5 25.0
Vertice 6 115.0
Vertice 7 165.0
A partir do vertice 3:
Menor Caminho para o
Vertice 0 [3, 2, 0]
Vertice 1 [3, 2, 1]
Vertice 2 [3, 2]
Vertice 3 [3]
Vertice 4 [3, 2, 0, 4]
Vertice 5 [3, 2, 0, 5]
Vertice 6 [3, 2, 0, 6]
Vertice 7 [3, 2, 0, 7]
Menor Distancia para o
Vertice 0 220.0
Vertice 1 200.0
Vertice 2 120.0
Vertice 3 0.0
Vertice 4 3.4028234663852886E38
Vertice 5 3.4028234663852886E38
Vertice 6 3.4028234663852886E38
Vertice 7 3.4028234663852886E38
A partir do vertice 1:
Menor Caminho para o
Vertice 0 [1, 0]
Vertice 1 [1]
Vertice 2 [1, 0, 2]
Vertice 3 [1, 0, 3]
Vertice 4 [1, 0, 4]
Vertice 5 [1, 0, 5]
Vertice 6 [1, 0, 6]
Vertice 7 [1, 0, 7]
Menor Distancia para o
Vertice 0 30.0
Vertice 1 0.0
Vertice 2 3.4028234663852886E38
Vertice 3 3.4028234663852886E38
Vertice 4 3.4028234663852886E38
Vertice 5 3.4028234663852886E38
Vertice 6 3.4028234663852886E38
Vertice 7 3.4028234663852886E38
-------------------------------
Eu desenhei o grafo, (pena não poder postar aqui) e encontrei diversas inconsistências, mais analisando apenas os dados, para o vértice 4:
Vertice 1 [4, 5, 3, 2, 1]
Existe o caminho 4-5-3-2-1, observe o caminho 2-1
Agora para o vértice 1:
Vertice 2 [1, 0, 2]
Ele passa pelo zero, quando deveria ir direto para o nodo 2..., e mesmo que houvesse este caminho, ao calcular a distância, ele indica que este caminho não é possível:
Vertice 2 3.4028234663852886E38
0 0 * * * * * * *
1 30 0 * * * * * *
2 100 80 0 * * * * *
3 * * 120 0 * * * *
4 * * * 150 0 25 * *
5 * * * 100 * 0 90 140
6 * * * * * * 0 100
7 170 * * * * * * 0
Vc confundiu os índices. Vc tratou o índice 4 como 3 e o 2 como 1.
Na implementação quando vc passa 2 ele usa o índice [2] (0,1,2), ou seja, o terceiro vértice.
Veja com mais calma os índices.
Essa implementação foi certificada por um professor Doutor da USP que ministra as disciplinas Algoritmos e estruturas de dados I e II.
Ele executou esse código do meu lado para todos os casos e não achou erro (inclusive esse grafo foi o primeiro que ele testou).
E se vc ainda achar que a implementação está errado dê uma olhada no pseudo-código do dijkstra e vc verá que são exatamente a mesma coisa.
Por favor, não insista no erro.
Não vou responder mais a pessoas confusas.
Mesmo assim, obrigado pela preocupação
Para provar que vc confundiu.
"Agora para o vértice 1:
Vertice 2 [1, 0, 2]
Ele passa pelo zero, quando deveria ir direto para o nodo 2...,"
Isso não tem o menor sentido.
Veja a linha.
30 0 * * * * * *
O 1 vai para o 0.
Não existe 1->2.
Estou iniciando o curso de grafos e não sei como abrir a matriz de adjacencia para ver como funciona o seu código.
Sou aluno da UFABC e gostaria de testar e pretendo sitar vc e deixarei como autor no código.
Se puder ajudar
grato
Boa noite,
Para você o que é abrir a matriz?
Inicializa-la? Acessa-la?
Olá Caio fiz a implementação do seu algoritmo e funcionou corretamente.Mas existe uma dúvida somente na escolha do vértice 2 ele causa um estouro de pilha.Realmente tentei observar o codigo e não consegui entender o porque.
Eu adaptei o seu algoritmo para uma matriz de 6 vértices e estarei implemnentando um trabalho para a faculdade com todos os méritos merecidos a sua implementação do código.Obrigado pelo seu valioso conhecimento.
Postar um comentário