Skip to content

Commit e198a50

Browse files
committed
added only implementation of A_STAR algorithem
1 parent ed88315 commit e198a50

File tree

1 file changed

+64
-2
lines changed

1 file changed

+64
-2
lines changed

pydatastructs/graphs/algorithms.py

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -700,12 +700,14 @@ def shortest_paths(graph: Graph, algorithm: str,
700700
'bellman_ford' -> Bellman-Ford algorithm as given in [1].
701701
702702
'dijkstra' -> Dijkstra algorithm as given in [2].
703+
704+
'A_star' -> A* algorithm as given in [3].
703705
source: str
704706
The name of the source the node.
705707
target: str
706708
The name of the target node.
707709
Optional, by default, all pair shortest paths
708-
are returned.
710+
are returned. Required for A* algorithm.
709711
backend: pydatastructs.Backend
710712
The backend to be used.
711713
Optional, by default, the best available
@@ -736,12 +738,20 @@ def shortest_paths(graph: Graph, algorithm: str,
736738
({'V1': 0, 'V2': 11, 'V3': 21}, {'V1': None, 'V2': 'V1', 'V3': 'V2'})
737739
>>> shortest_paths(G, 'dijkstra', 'V1')
738740
({'V2': 11, 'V3': 21, 'V1': 0}, {'V1': None, 'V2': 'V1', 'V3': 'V2'})
739-
741+
>>> start = AdjacencyListGraphNode("0,0")
742+
>>> middle = AdjacencyListGraphNode("1,1")
743+
>>> goal = AdjacencyListGraphNode("2,2")
744+
>>> G2 = Graph(start, middle, goal)
745+
>>> G2.add_edge('0,0', '1,1', 2)
746+
>>> G2.add_edge('1,1', '2,2', 2)
747+
>>> shortest_paths(G2, 'A_star', '0,0', '2,2')
748+
(4, {'0,0': None, '1,1': '0,0', '2,2': '1,1'})
740749
References
741750
==========
742751
743752
.. [1] https://en.wikipedia.org/wiki/Bellman%E2%80%93Ford_algorithm
744753
.. [2] https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
754+
.. [3] https://en.wikipedia.org/wiki/A*_search_algorithm
745755
"""
746756
raise_if_backend_is_not_python(
747757
shortest_paths, kwargs.get('backend', Backend.PYTHON))
@@ -811,6 +821,58 @@ def _dijkstra_adjacency_list(graph: Graph, start: str, target: str):
811821

812822
_dijkstra_adjacency_matrix = _dijkstra_adjacency_list
813823

824+
def _a_star_adjacency_list(graph: Graph, source: str, target: str) -> tuple:
825+
"""
826+
A* pathfinding algorithm implementation similar to Dijkstra's structure.
827+
828+
Parameters
829+
==========
830+
graph: Graph
831+
The graph to search through
832+
source: str
833+
Starting node name
834+
target: str
835+
Target node name
836+
837+
Returns
838+
=======
839+
(distance, predecessors): tuple
840+
Distance to target and dictionary of predecessors
841+
"""
842+
def heuristic(node: str, goal: str) -> float:
843+
"""Manhattan distance heuristic for A*"""
844+
x1, y1 = map(int, node.split(','))
845+
x2, y2 = map(int, goal.split(','))
846+
return abs(x1 - x2) + abs(y1 - y2)
847+
visited = {v: False for v in graph.vertices}
848+
dist = {v: float('inf') for v in graph.vertices}
849+
pred = {v: None for v in graph.vertices}
850+
dist[source] = 0
851+
# Priority queue using f-score (g_score + heuristic)
852+
pq = PriorityQueue(implementation='binomial_heap')
853+
pq.push(source, heuristic(source, target))
854+
while not pq.is_empty:
855+
current = pq.pop()
856+
if current == target:
857+
return dist[target], pred
858+
if visited[current]:
859+
continue
860+
visited[current] = True
861+
for neighbor in graph.neighbors(current):
862+
if visited[neighbor.name]:
863+
continue
864+
edge = graph.get_edge(current, neighbor.name)
865+
if not edge:
866+
continue
867+
new_dist = dist[current] + edge.value
868+
if new_dist < dist[neighbor.name]:
869+
dist[neighbor.name] = new_dist
870+
pred[neighbor.name] = current
871+
f_score = new_dist + heuristic(neighbor.name, target)
872+
pq.push(neighbor.name, f_score)
873+
return float('inf'), pred
874+
_a_star_adjacency_matrix = _a_star_adjacency_list
875+
814876
def all_pair_shortest_paths(graph: Graph, algorithm: str,
815877
**kwargs) -> tuple:
816878
"""

0 commit comments

Comments
 (0)