mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-01-18 16:27:02 +00:00
Add shortest path by BFS (#1870)
* Create breadth_first_search_shortest_path.py * updating DIRECTORY.md * Reduce side effect of `shortest_path` For the sake of future testing and documentation - * fixup! Format Python code with psf/black push * Fix typo `separately` * Change to get() from dictionary Co-Authored-By: Christian Clauss <cclauss@me.com> * Move graph to the top * fixup! Format Python code with psf/black push * Add doctest for shortest path * Add doctest for BFS * fixup! Format Python code with psf/black push * Add typings for breadth_first_search_shortest_path * fixup! Format Python code with psf/black push * Remove assert from doctests * Add blank line to doctest Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Co-authored-by: John Law <johnlaw.po@gmail.com> Co-authored-by: Christian Clauss <cclauss@me.com> Co-authored-by: John Law <johnlaw@linux.com>
This commit is contained in:
parent
b01e5b78a3
commit
308505f18f
|
@ -213,6 +213,7 @@
|
|||
* [Bfs](https://github.com/TheAlgorithms/Python/blob/master/graphs/bfs.py)
|
||||
* [Bfs Shortest Path](https://github.com/TheAlgorithms/Python/blob/master/graphs/bfs_shortest_path.py)
|
||||
* [Breadth First Search](https://github.com/TheAlgorithms/Python/blob/master/graphs/breadth_first_search.py)
|
||||
* [Breadth First Search Shortest Path](https://github.com/TheAlgorithms/Python/blob/master/graphs/breadth_first_search_shortest_path.py)
|
||||
* [Check Bipartite Graph Bfs](https://github.com/TheAlgorithms/Python/blob/master/graphs/check_bipartite_graph_bfs.py)
|
||||
* [Check Bipartite Graph Dfs](https://github.com/TheAlgorithms/Python/blob/master/graphs/check_bipartite_graph_dfs.py)
|
||||
* [Depth First Search](https://github.com/TheAlgorithms/Python/blob/master/graphs/depth_first_search.py)
|
||||
|
|
81
graphs/breadth_first_search_shortest_path.py
Normal file
81
graphs/breadth_first_search_shortest_path.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
"""Breath First Search (BFS) can be used when finding the shortest path
|
||||
from a given source node to a target node in an unweighted graph.
|
||||
"""
|
||||
graph = {
|
||||
"A": ["B", "C", "E"],
|
||||
"B": ["A", "D", "E"],
|
||||
"C": ["A", "F", "G"],
|
||||
"D": ["B"],
|
||||
"E": ["A", "B", "D"],
|
||||
"F": ["C"],
|
||||
"G": ["C"],
|
||||
}
|
||||
|
||||
from typing import Dict
|
||||
|
||||
|
||||
class Graph:
|
||||
def __init__(self, graph: Dict[str, str], source_vertex: str) -> None:
|
||||
"""Graph is implemented as dictionary of adjancency lists. Also,
|
||||
Source vertex have to be defined upon initialization.
|
||||
"""
|
||||
self.graph = graph
|
||||
# mapping node to its parent in resulting breadth first tree
|
||||
self.parent = {}
|
||||
self.source_vertex = source_vertex
|
||||
|
||||
def breath_first_search(self) -> None:
|
||||
"""This function is a helper for running breath first search on this graph.
|
||||
>>> g = Graph(graph, "G")
|
||||
>>> g.breath_first_search()
|
||||
>>> g.parent
|
||||
{'G': None, 'C': 'G', 'A': 'C', 'F': 'C', 'B': 'A', 'E': 'A', 'D': 'B'}
|
||||
"""
|
||||
visited = {self.source_vertex}
|
||||
self.parent[self.source_vertex] = None
|
||||
queue = [self.source_vertex] # first in first out queue
|
||||
|
||||
while queue:
|
||||
vertex = queue.pop(0)
|
||||
for adjancent_vertex in self.graph[vertex]:
|
||||
if adjancent_vertex not in visited:
|
||||
visited.add(adjancent_vertex)
|
||||
self.parent[adjancent_vertex] = vertex
|
||||
queue.append(adjancent_vertex)
|
||||
|
||||
def shortest_path(self, target_vertex: str) -> str:
|
||||
"""This shortest path function returns a string, describing the result:
|
||||
1.) No path is found. The string is a human readable message to indicate this.
|
||||
2.) The shortest path is found. The string is in the form `v1(->v2->v3->...->vn)`,
|
||||
where v1 is the source vertex and vn is the target vertex, if it exists separately.
|
||||
|
||||
>>> g = Graph(graph, "G")
|
||||
>>> g.breath_first_search()
|
||||
|
||||
Case 1 - No path is found.
|
||||
>>> g.shortest_path("Foo")
|
||||
'No path from vertex:G to vertex:Foo'
|
||||
|
||||
Case 2 - The path is found.
|
||||
>>> g.shortest_path("D")
|
||||
'G->C->A->B->D'
|
||||
>>> g.shortest_path("G")
|
||||
'G'
|
||||
"""
|
||||
if target_vertex == self.source_vertex:
|
||||
return f"{self.source_vertex}"
|
||||
elif not self.parent.get(target_vertex):
|
||||
return f"No path from vertex:{self.source_vertex} to vertex:{target_vertex}"
|
||||
else:
|
||||
return self.shortest_path(self.parent[target_vertex]) + f"->{target_vertex}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import doctest
|
||||
|
||||
doctest.testmod()
|
||||
g = Graph(graph, "G")
|
||||
g.breath_first_search()
|
||||
print(g.shortest_path("D"))
|
||||
print(g.shortest_path("G"))
|
||||
print(g.shortest_path("Foo"))
|
Loading…
Reference in New Issue
Block a user