O "algoritmo mais rápido do caminho mais curto" depende fortemente das características específicas do seu gráfico:
1. Natureza do gráfico: *
ponderado vs. não ponderado: As bordas do seu gráfico estão associadas a um custo ou distância (ponderadas), ou todas as bordas são consideradas como tendo o mesmo custo (não ponderado)?
*
Dirigido vs. não direcionado: As bordas são direcionais (ruas de ida) ou bidirecional (ruas de mão dupla)?
*
cíclico vs. aciclico: O gráfico contém ciclos (caminhos que podem levar de volta ao mesmo nó)?
* densidade
: O gráfico é escasso (relativamente poucas bordas) ou denso (muitas bordas)?
*
pesos não negativos: Todos os pesos da borda são não negativos? Isso é * crucial * para muitos algoritmos funcionarem corretamente. Se você tiver pesos negativos, é necessário um manuseio especial.
*
euclidiano vs. não-euclidiano: Você pode usar propriedades geométricas para inferir distâncias entre pontos?
2. Objetivo do algoritmo: *
Caminho mais curto de fonte única: Encontrando o caminho mais curto de um nó inicial específico para todos os outros nós no gráfico.
*
Caminho mais curto de destinação única: Encontrar o caminho mais curto de todos os nós para um nó de destino específico (conceitualmente o mesmo que o código único se você reverter a direção das bordas).
*
All-Par-Pada mais curta Caminho: Encontrando o caminho mais curto entre * todos os * pares de nós no gráfico.
*
heurísticas permitidas? Se você está bem com uma aproximação e não garantiu o caminho * absoluto * mais curto, muitas vezes pode obter resultados muito mais rápidos com a pesquisa heurística.
Aqui está um colapso de algoritmos comuns e seus casos de uso típicos: Para gráficos não ponderados: *
Pesquisa em largura (BFS): Este é o algoritmo * mais rápido * e mais simples para gráficos não ponderados. Ele garante encontrar o caminho mais curto (em termos do número * de bordas) de um nó de origem para todos os outros nós acessíveis.
*
complexidade do tempo: O (v + e) onde v é o número de vértices e e é o número de arestas.
Para gráficos pesados com pesos não negativos: *
Algoritmo de Dijkstra: Um dos algoritmos mais amplamente utilizados para encontrar o caminho mais curto de uma única fonte para todos os outros nós em um gráfico ponderado com pesos * não negativos * da borda.
*
complexidade do tempo: * O (v^2) (com uma matriz simples ou implementação de lista para fila prioritária)
* O (E + V log V) (usando uma pilha binária ou fila de prioridade)
* O (E + V log* V) (usando pilhas de fibonacci - menos comum na prática devido à sobrecarga)
*
a* pesquisa: Uma extensão do algoritmo de Dijkstra que usa uma função * heurística * para orientar a pesquisa. Muitas vezes, é significativamente mais rápido que o de Dijkstra quando você tem boas informações heurísticas sobre a distância restante do destino.
*
complexidade do tempo: Depende da heurística. Na melhor das hipóteses (heurística perfeita), pode ser muito rápido. Na pior das hipóteses (má heurística), pode ser tão lento quanto o de Dijkstra.
*
a* requer uma heurística que é admissível (nunca superestima o custo para atingir a meta) e consistente (monotônico). Para gráficos pesados com pesos negativos (e sem ciclos negativos): *
Algoritmo Bellman-Ford: Pode lidar com gráficos com pesos negativos da borda, desde que não haja ciclos negativos (ciclos onde a soma dos pesos da borda é negativa). Se existir um ciclo negativo, pode detectá -lo.
*
complexidade do tempo: O (v * e)
para os pares de todos os caminhos mais curtos: *
algoritmo Floyd-Warshall: Encontra o caminho mais curto entre * todos os * pares de vértices em um gráfico direcionado ou não direcionado. Também pode lidar com pesos de borda negativos (mas não ciclos negativos).
*
complexidade do tempo: O (v^3)
*
Algoritmo de Johnson: Também pode encontrar caminhos mais curtos de todos os pares e pode lidar com pesos de borda negativos. Geralmente é mais rápido que o Floyd-Warshall nos gráficos * esparsos *. Funciona repondo as bordas para eliminar pesos negativos (usando Bellman-Ford) e depois executando o algoritmo de Dijkstra de cada vértice.
*
complexidade do tempo: O (v^2 log V + ve)
Tabela de resumo | Algoritmo | Tipo de gráfico | Pesos da borda | Complexidade do tempo | Notas |
| -------------------- | ----------------------------------------------- | ------------ | ---------------------------- | --------------------------------------------------------------- |
| BFS | Não ponderado | Nenhum | O (V + E) | Mais rápido para gráficos não ponderados. |
| Dijkstra's | Ponderado, não negativo | Não negativo | O (E + V log V) | Comum, funciona bem com fila de prioridade. |
| A* | Ponderado, não negativo | Não negativo | Dependente heurístico | Pode ser muito mais rápido que a de Dijkstra se houver uma boa heurística. |
| Bellman-Ford | Ponderado, pode ter bordas negativas | Qualquer | O (v * e) | Pode detectar ciclos negativos. |
| Floyd-Warshall | Ponderado, pode ter bordas negativas (sem ciclos) | Qualquer | O (v^3) | Caminhos mais curtos de todos os pares, bons para gráficos densos. |
| Johnson's | Ponderado, pode ter bordas negativas (sem ciclos) | Qualquer | O (v^2 log V + ve) | Caminhos mais curtos de todos os pares, melhor do que Floyd-Warshall para gráficos esparsos |
Considerações e otimizações práticas: *
Estruturas de dados: A escolha da estrutura de dados para a fila de prioridade no algoritmo de Dijkstra (por exemplo, heap binário, heap fibonacci) pode afetar significativamente o desempenho, especialmente para gráficos grandes.
*
heurísticas para A*: Escolher uma boa heurística para um* é crucial. Uma heurística bem escolhida pode acelerar drasticamente a pesquisa. As heurísticas comuns incluem distância euclidiana (para gráficos incorporados em um avião) e distância de Manhattan.
*
Representação gráfica: A maneira como você representa seu gráfico (por exemplo, lista de adjacência, matriz de adjacência) também pode afetar o desempenho. As listas de adjacência são geralmente preferidas para gráficos esparsos, enquanto as matrizes de adjacência podem ser mais eficientes para gráficos densos.
*
pré -processamento: Para gráficos que são consultados repetidamente, você pode pré -computar determinadas informações (por exemplo, marcos, árvores de caminho mais curto) para acelerar as consultas subsequentes.
*
Redes de estradas no mundo real: Para redes rodoviárias, algoritmos especializados, como hierarquias de contração (CH) e planejamento de rota personalizável (CRP), oferecem * muito mais tempo de consulta mais rápidos do que os algoritmos genéricos como o Dijkstra, mas requerem pré -processamento significativo. Estes são frequentemente usados em sistemas de navegação por GPS.
*
Bibliotecas: Use bibliotecas otimizadas (por exemplo, Networkx em Python, Jgrapht em Java) sempre que possível. Essas bibliotecas geralmente fornecem implementações altamente otimizadas dos algoritmos de caminho mais curtos.
em resumo, para determinar o algoritmo "mais rápido" para a sua situação: 1.
caracterizar seu gráfico: É ponderado, não ponderado, direcionado, escasso, denso, etc.?
2.
você precisa de caminhos mais curtos de fonte única ou de todos os pares? 3.
estão presentes os pesos da borda? Nesse caso, você está limitado a Bellman-Ford (Sprimento único) ou Johnson/Floyd-Warshall (todos os pares).
4.
Se pesos não negativos, considere Dijkstra's ou A*. Se A*, você pode criar uma boa heurística? 5.
Para gráficos não ponderados, o BFS é quase sempre a melhor escolha. 6.
perfil e referência: Experimente algoritmos e estruturas de dados diferentes para ver qual desempenho melhor no seu conjunto de dados e hardware específico.
Escolha o algoritmo mais simples que atenda às suas necessidades. Não use o Floyd-Warshall se você precisar apenas de caminhos mais curtos de fonte única.