*A (A-star)** is a best-first search algorithm used to find the shortest path in a weighted graph or grid, combining the strengths of Dijkstra’s algorithm (which finds the shortest path from a start node to all others) and greedy best-first search (which prioritizes nodes that appear closer to the target). A* uses a heuristic function to guide its search toward the target, making it far more efficient than unguided search algorithms like BFS or Dijkstra’s for most pathfinding tasks.
A* is the de facto standard for pathfinding in games, robotics, and GPS navigation, as it balances optimality (guarantees the shortest path if the heuristic is admissible) and efficiency (avoids exploring irrelevant paths).
Core Principles of A* Algorithm
A* evaluates each node by calculating a cost function f(n) for the node n, which is the sum of two components:
\(f(n) = g(n) + h(n)\)
g(n): The actual cost from the start node to the current noden(this is the exact cost of the path taken to reachn).h(n): The heuristic estimate of the cost from the current nodento the target node (this is a guess—its quality determines the algorithm’s efficiency).
Key Heuristic Requirements
For A* to guarantee the shortest path (optimality), the heuristic h(n) must be:
- Admissible:
h(n) ≤ actual cost from n to target(the heuristic never overestimates the true cost). - Consistent (Monotonic): For any node
nand its neighborn',h(n) ≤ cost(n → n') + h(n')(the heuristic estimate fornis no more than the cost to move ton'plus the heuristic estimate forn').
Common Heuristics
The choice of heuristic depends on the problem domain:
- Grid Pathfinding (2D):
- Manhattan Distance (for grid movement restricted to 4 directions: up/down/left/right):\(h(n) = |x_n – x_{target}| + |y_n – y_{target}|\)
- Euclidean Distance (for free movement in any direction):\(h(n) = \sqrt{(x_n – x_{target})^2 + (y_n – y_{target})^2}\)
- Chebyshev Distance (for grid movement allowed in 8 directions):\(h(n) = max(|x_n – x_{target}|, |y_n – y_{target}|)\)
- Graphs: Custom heuristics based on domain knowledge (e.g., straight-line distance for road networks).
A* Search Process
- Initialize:
- Create an open set (priority queue) to track nodes to be explored, sorted by
f(n)(lowest first). Start with the start node (g(start) = 0,f(start) = h(start)). - Create a closed set (hash set) to track nodes that have already been processed (to avoid reprocessing).
- Keep a
came_fromdictionary to reconstruct the path once the target is found.
- Create an open set (priority queue) to track nodes to be explored, sorted by
- Iterate: While the open set is not empty:
- Extract the node
currentwith the lowestf(n)from the open set. - If
currentis the target, reconstruct the path usingcame_fromand return it. - Add
currentto the closed set. - For each neighbor of
current:- If the neighbor is in the closed set, skip it.
- Calculate
tentative_g = g(current) + cost(current → neighbor)(the cost to reach the neighbor viacurrent). - If the neighbor is not in the open set, or
tentative_gis lower than the existingg(neighbor)(a better path to the neighbor is found):- Update
g(neighbor) = tentative_gandf(neighbor) = g(neighbor) + h(neighbor). - Set
came_from(neighbor) = current. - Add the neighbor to the open set (or update its priority if already present).
- Update
- Extract the node
- Terminate: If the open set is empty and the target was not found, no path exists.
A* Algorithm Implementation (Python)
We implement A* for 2D grid pathfinding (4-directional movement) using Manhattan distance as the heuristic. The grid uses 0 for walkable cells and 1 for obstacles.
Full Implementation
python
运行
import heapq
def a_star(grid, start, target):
"""
A* algorithm for 2D grid pathfinding (4-directional movement).
Args:
grid (list): 2D list of 0s (walkable) and 1s (obstacles).
start (tuple): (x, y) coordinates of the start node.
target (tuple): (x, y) coordinates of the target node.
Returns:
list: Shortest path from start to target (list of (x,y) tuples), or None if no path exists.
"""
# Check if start/target are valid (within grid and not obstacles)
rows = len(grid)
cols = len(grid[0]) if rows > 0 else 0
def is_valid(x, y):
return 0 <= x < rows and 0 <= y < cols and grid[x][y] == 0
if not is_valid(*start) or not is_valid(*target):
return None
# Heuristic: Manhattan distance (admissible for 4-directional movement)
def heuristic(node):
x, y = node
tx, ty = target
return abs(x - tx) + abs(y - ty)
# Open set: priority queue of (f(n), x, y) — sorted by f(n)
open_set = []
heapq.heappush(open_set, (heuristic(start), start[0], start[1]))
# Dictionaries to track g(n), f(n), and parent nodes
g_score = {start: 0}
f_score = {start: heuristic(start)}
came_from = {}
# 4-directional movement (up, down, left, right)
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
while open_set:
# Extract node with lowest f(n)
current_f, x, y = heapq.heappop(open_set)
current = (x, y)
# Target found: reconstruct path
if current == target:
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
return path[::-1] # Reverse to get start → target
# Process neighbors
for dx, dy in directions:
neighbor = (x + dx, y + dy)
if not is_valid(*neighbor):
continue # Skip obstacles or out-of-bounds nodes
# Tentative g score: cost from start to neighbor via current
tentative_g = g_score[current] + 1 # Assume each step has cost 1
# If neighbor not in g_score or tentative_g is better (shorter path)
if neighbor not in g_score or tentative_g < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f_score[neighbor] = tentative_g + heuristic(neighbor)
# Add to open set if not already present
if (f_score[neighbor], neighbor[0], neighbor[1]) not in open_set:
heapq.heappush(open_set, (f_score[neighbor], neighbor[0], neighbor[1]))
# No path found
return None
# Test the A* algorithm
if __name__ == "__main__":
# Sample grid: 0 = walkable, 1 = obstacle
grid = [
[0, 0, 0, 0, 1],
[0, 1, 1, 0, 0],
[0, 0, 0, 1, 0],
[1, 1, 0, 0, 0],
[0, 0, 0, 0, 0]
]
start = (0, 0)
target = (4, 4)
shortest_path = a_star(grid, start, target)
if shortest_path:
print("Shortest Path (start → target):")
print(shortest_path)
else:
print("No path found between start and target.")
Sample Output
For the test grid above, the output will be a list of coordinates representing the shortest path (e.g.):
plaintext
Shortest Path (start → target):
[(0, 0), (1, 0), (2, 0), (2, 1), (2, 2), (3, 2), (3, 3), (3, 4), (4, 4)]
Time and Space Complexity
The complexity of A* depends heavily on the heuristic quality and the structure of the graph/grid:
| Metric | Worst Case | Best Case (Perfect Heuristic) | Explanation |
|---|---|---|---|
| Time Complexity | O(b^d) | O(d) | b = branching factor (number of neighbors per node), d = depth of the shortest path. In the worst case (admissible but uninformative heuristic like h(n)=0), A* degenerates to Dijkstra’s algorithm (O(E + V log V) for graphs). |
| Space Complexity | O(b^d) | O(d) | The open set and closed set can store up to b^d nodes in the worst case. For grids, this is often O(W×H) (grid width × height). |
Key Notes:
- A perfect heuristic (
h(n) = actual cost from n to target) makes A* jump directly to the target, resulting in O(d) time/space. - A poor heuristic (e.g.,
h(n) = 0) reduces A* to Dijkstra’s algorithm, which explores all nodes with the lowestg(n)first. - A non-admissible heuristic (overestimates the cost) may find a faster path but does not guarantee the shortest path.
Pros and Cons of A* Algorithm
Pros
- Optimal: Guarantees the shortest path if the heuristic is admissible (never overestimates the true cost).
- Efficient: The heuristic guides the search toward the target, avoiding irrelevant paths (far faster than Dijkstra’s or BFS for most pathfinding tasks).
- Flexible: Works for graphs, grids, and arbitrary pathfinding domains (e.g., robotics, game AI) with custom heuristics.
- Complete: Finds a path if one exists (assuming the branching factor is finite and the heuristic is admissible).
Cons
- Heuristic Dependence: Performance is highly sensitive to the heuristic— a bad heuristic (e.g., uninformative or non-admissible) leads to slow search or suboptimal paths.
- Memory Intensive: Requires storing the open set and closed set, which can be prohibitive for very large grids/graphs (e.g., global GPS navigation).
- Not Suitable for Dynamic Environments: Struggles with grids/graphs that change in real time (e.g., moving obstacles in a game)—requires re-running the algorithm from scratch.
- Complex for Unweighted Graphs: BFS is simpler and more efficient for unweighted pathfinding (A* adds heuristic overhead with no benefit).
Real-World Applications of A* Algorithm
- Game Development: Pathfinding for NPCs (non-player characters) in video games (e.g., Minecraft, Pokémon, or strategy games) to navigate around obstacles.
- Robotics: Autonomous robots (e.g., self-driving cars, delivery drones, warehouse robots) use A* to plan collision-free paths in dynamic or static environments.
- GPS Navigation: Mapping services (Google Maps, Apple Maps) use A* (or variants like Contraction Hierarchies) to find the shortest/fastest route between two locations in road networks.
- Maze Solving: A* is used to solve complex mazes efficiently, often outperforming BFS or DFS by focusing on the target.
- Network Routing: Data packet routing in computer networks uses A*-like heuristics to find the shortest path between routers (minimizing latency or bandwidth usage).
- Path Planning in CAD/CAM: Computer-aided design and manufacturing use A* to plan tool paths for CNC machines (avoiding collisions with workpieces).
Summary
Best use cases: Weighted grid/graph pathfinding in games, robotics, and GPS navigation.
A* is a best-first search algorithm that uses f(n) = g(n) + h(n) to guide pathfinding toward the target.
Key requirement: An admissible heuristic guarantees the shortest path.
Time/space complexity depends on the heuristic—ranges from O(d) (perfect heuristic) to O(b^d) (worst case).
- High-Performance Waterproof Solar Connectors
- Durable IP68 Waterproof Solar Connectors for Outdoor Use
- High-Quality Tinned Copper Material for Durability
- High-Quality Tinned Copper Material for Long Service Life
- Y Branch Parallel Solar Connector for Enhanced Power
- 10AWG Tinned Copper Solar Battery Cables
- NEMA 5-15P to Powercon Extension Cable Overview
- Dual Port USB 3.0 Adapter for Optimal Speed
- 4-Pin XLR Connector: Reliable Audio Transmission
- 4mm Banana to 2mm Pin Connector: Your Audio Solution
- 12GB/s Mini SAS to U.2 NVMe Cable for Fast Data Transfer
- CAB-STK-E Stacking Cable: 40Gbps Performance
- High-Performance CAB-STK-E Stacking Cable Explained
- Best 10M OS2 LC to LC Fiber Patch Cable for Data Centers
- Mini SAS HD Cable: Boost Data Transfer at 12 Gbps
- Multi Rate SFP+: Enhance Your Network Speed
- Best 6.35mm to MIDI Din Cable for Clear Sound
- 15 Pin SATA Power Splitter: Solutions for Your Device Needs
- 9-Pin S-Video Cable: Enhance Your Viewing Experience
- USB 9-Pin to Standard USB 2.0 Adapter: Easy Connection
- 3 Pin to 4 Pin Fan Adapter: Optimize Your PC Cooling
- S-Video to RCA Cable: High-Definition Connections Made Easy
- 6.35mm TS Extension Cable: High-Quality Sound Solution
- BlackBerry Curve 9360: Key Features and Specs






















Leave a comment