一、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 List FindPath(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演算法的缺點:
- 對數據結構要求較高
- 啟發函數的設計非常重要,不好的啟發函數可能導致演算法性能下降
- 有可能陷入局部最優解
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/244630.html