一、Astar算法c
Astar算法(A*)是一种常用的寻路算法,因为它可以在一张地图中找到最短路径,并且计算量不大,所以被广泛应用于自动化寻路系统,游戏中的NPC移动等方面。A*算法的思路是在搜索过程中维护一个开放列表和一个封闭列表,搜索过程中通过启发式函数预测此路径的长度,来选择最优的路径。使用C语言实现A*算法如下:
void Astar() { while(!openList.empty()) { AstarPt* present = openList.top(); openList.pop(); if (present->row == endPt->row && present->col == endPt->col) { endPt->pre = present->pre; return; } closeList.push_back(present); getSuccessors(present); } }
二、Astar算法与Dijkstra算法
Astar算法与Dijkstra算法都是用于寻路问题的经典算法。Dijkstra算法是一种基于图论的贪心算法,在某些特殊情况下可能会陷入死循环,而Astar算法不会。Astar算法在计算过程中预测剩余距离,因此总是朝着目标方向前进,相比于Dijkstra算法,它更加高效。而Dijkstra算法要求每个路径权值都为正数,因为它在计算时会扩展所有相邻节点,网格地图中代价计算比较困难。因此,对于需要在网格地图上搜索路径的问题,Astar算法是更好的选择。
三、Astar算法原理
Astar算法维护两个列表:开放列表和封闭列表。初始时,将起点放入开放列表中。在每次循环中,从开放列表中选取预估代价最小的节点出队,并将其放入封闭列表中。接下来,通过计算预估剩余距离将当前节点的邻居入队到开放列表中。在路径被找到之前,重复执行此过程。当路径被找到时,从终点开始遍历每个节点的pre指针,直到回到起始节点,即可得到这条路径。
四、Astar算法Python
Python语言实现Astar算法非常方便,以下是一个简单的实现例子:
def Astar(start, end, graph): openList = PriorityQueue() openList.put(start, 0) cameFrom = {} gScore = defaultdict(lambda: float('inf')) gScore[start] = 0 fScore = defaultdict(lambda: float('inf')) fScore[start] = heuristic(start, end) while not openList.empty(): current = openList.get() if current == end: return construct_path(cameFrom, start, end) for neighbor in graph[current]: tentative_gScore = gScore[current] + graph[current][neighbor] if tentative_gScore < gScore[neighbor]: cameFrom[neighbor] = current gScore[neighbor] = tentative_gScore fScore[neighbor] = tentative_gScore + heuristic(neighbor, end) if neighbor not in openList.queue: openList.put(neighbor, fScore[neighbor]) return "No path"
五、Astar算法代码
以下是一个简单的伪代码实现:
function A* (start,goal) closedList := {}; //已被评估过的点 openList := {}; //待评估的点 visitedFrom := {}; //记录每个点来自于哪个点 gScore := {}; //从起始点到此点已经花费的代价 fScore := {}; //总代价 = 已花费的代价 + 剩余代价 push start into openList gScore[start] := 0 fScore[start] := gScore[start] + heuristic_cost_estimate(start, goal) while openList is not empty current := the node in openList having the lowest fScore[] value if current = goal return reconstruct_path(visitedFrom,goal) remove current from openList push current into closedList for each neighbor in neighbor_nodes(current) if neighbor in closedList continue tentative_gScore := gScore[current] + distance_between(current,neighbor) if neighbor not in openList or tentative_gScore < gScore[neighbor] visitedFrom[neighbor] := current gScore[neighbor] := tentative_gScore fScore[neighbor] := gScore[neighbor] + heuristic_cost_estimate(neighbor, goal) if neighbor not in openList push neighbor into openList return failure
六、Astar算法例子
以下是一个基于地图的Astar算法例子:
def heuristic_cost_estimate(current, goal): return abs(current.x - goal.x) + abs(current.y - goal.y) def reconstruct_path(visitedFrom, current): total_path = [current] while current in visitedFrom: current = visitedFrom[current] total_path.append(current) return total_path def Astar(start, goal, graph): closedList = [] openList = [start] visitedFrom = {} gScore = {start: 0} fScore = {start: heuristic_cost_estimate(start, goal)} while openList: current = min(openList, key=lambda x:fScore[x]) if current == goal: return reconstruct_path(visitedFrom, current) openList.remove(current) closedList.append(current) for neighbor in graph[current]: if neighbor in closedList: continue tentative_gScore = gScore[current] + graph[current][neighbor] if neighbor not in openList or tentative_gScore < gScore[neighbor]: visitedFrom[neighbor] = current gScore[neighbor] = tentative_gScore fScore[neighbor] = gScore[neighbor] + heuristic_cost_estimate(neighbor, goal) if neighbor not in openList: openList.append(neighbor) return "No path"
七、Astar算法寻路
在游戏开发中,Astar算法可以被用于寻路,以下是一个简单的寻路实现例子:
public class AstarPathfinding : MonoBehaviour { Node startNode; Node endNode; public ListFindPath(Node start, Node end) { startNode = start; endNode = end; List openSet = new List (); HashSet closedSet = new HashSet (); openSet.Add(startNode); while (openSet.Count > 0) { Node currentNode = openSet[0]; for (int i = 1; i < openSet.Count; i++) { if (openSet[i].fCost < currentNode.fCost || openSet[i].fCost == currentNode.fCost && openSet[i].hCost < currentNode.hCost) { currentNode = openSet[i]; } } openSet.Remove(currentNode); closedSet.Add(currentNode); if (currentNode == endNode) { return RetracePath(startNode, endNode); } foreach (Node neighbor in currentNode.neighbors) { if (!neighbor.walkable || closedSet.Contains(neighbor)) { continue; } int newCostToNeighbor = currentNode.gCost + GetDistance(currentNode, neighbor); if (newCostToNeighbor < neighbor.gCost || !openSet.Contains(neighbor)) { neighbor.gCost = newCostToNeighbor; neighbor.hCost = GetDistance(neighbor, endNode); neighbor.parent = currentNode; if (!openSet.Contains(neighbor)) { openSet.Add(neighbor); } } } } return null; } //... }
八、Astar算法和贪心算法
贪心算法和Astar算法有着类似的思路,都是在计算过程中维护一个开放列表和一个封闭列表,且都使用启发式函数来决定哪个节点应该被扩展。但贪心算法只考虑当前扩展节点,而Astar算法还要考虑目标节点的距离,这使它变得更符合现实情况。Astar算法相对于贪心算法来说,能够找到更优的路径。
九、Astar算法优化
Astar算法的运行效率取决于启发函数的选择和数据结构的优化。设计一个好的启发函数非常重要,它决定了算法的速度和精度。另外,在实际的应用过程中可以采用一些优化策略来加速运算,如减少存储空间、预处理数据等。
十、Astar算法的优缺点
Astar算法的优点:
- 可以找到最短路径
- 启发式搜索可以减少搜索的时间和空间
- 应用广泛,特别是在游戏AI、数据挖掘等领域
Astar算法的缺点:
- 对数据结构要求较高
- 启发函数的设计非常重要,不好的启发函数可能导致算法性能下降
- 有可能陷入局部最优解