Loading

A星

A星算法的工作方式与迪杰斯特拉算法的工作方式大致相同,但迭代过程选择的是最短整体路径的节点而不是始终考虑具有最小Cost-So-Far值的开放节点。根据启发式计算方式的不同,其算法效率也是不同的,算法准确即高效否则甚至不如迪杰斯特拉算法。

算法过程:

1.处理当前节点

​ 在迭代期间,A星算法会考虑从当前节点发出的每个连接,计算到达终端节点的总成本以及终端节点所拥有的连接。此外,每个终端节点都会存储一个此节点到目标节点的路径总成本的估计值,可称为估计总成本。该估计总成本通常由目前的成本和到目标点的距离组成。这些估计值被称作该节点的启发式值,且该值是非负的。

2.节点列表

​ A星算法会保留已访问但未处理的开放节点列表以及已处理的封闭节点列表。当发现可连接的新节点时,该节点会被移入开放列表。当该节点处理完成时,会被移入封闭列表。

3.计算开放和封闭节点的Cost-So-Far值

​ 计算Cost-So-Far值时可能新值小于该节点的现有值,这时需要更新该值。A星算法在迭代过程中可能找到比已经在封闭列表中的节点更好的路线,这时需要将封闭节点中的节点重新放回开放列表中,之后对其自身和其连接的节点重新计算。

4.终止算法

​ 为保证A星算法运行地更充分,可以将A星算法地终止条件设置为在具有最小地Cost-So-Far值得开放列表中,节点所具有得Cost-So-Far值大于已找到的到达目标的路径成本。

5.检索路径

​ 从目标节点回溯到起始节点,于此同时累积连接。最后再次反转连接即可形成正确的路径。

伪代码:

class NodeRecord:
	node:Node
	connection:Connection
	costSoFar:float
	estimatedTotalCost:float
function pathfindAStar(	gragh:Graph,
			start:Node,
			goal:Node,
			heuristic:Heuristic) -> Connection[]:
	
	startRecord = new NodeRecord()
	startRecord.node = start
	startRecord.connection = null
	startRecord.costSoFar = 0
	startRecord.estimatedTotalCost = heuristic.estimate(start)
	
	open = new PathfindingList()
	open += startRecord
	closed = new PathfindingList()
	
	while length(open) > 0:
		current = open.smallestElement()
		if current.node == goal:
			break
		connections = gragh.getConnections(current)
		for connection in connections:
			endNode = connection.getToNode()
			endNodeCost = current.costSoFar + connection.getCost()
			
			if closed.contains(endNode):
				endNodeRecord = closed.find(endNode)
				if endNodeRecord.costSoFar <= endNodeCost:
					continue
				closed -= endNodeRecord
				endNodeHeuristic = endNodeRecord.cost - endNodeRecord.costSoFar
			else:
				endNodeRecord = new NodeRecord()
				endNodeRecord.node = endNode
				endNodeHeuristic = heuristic.estimate(endNode)
				
            endNodeRecord.cost = endNodeCost
            endNodeRecord.connection = connection
            endNodeRecord.estimatedTotalCost = endNodeCost + endNodeHeuristic
            if not open.contain(endNode):
            	open += endNodeRecord
            
        open -= current
        closed += current
    
    if current.node != goal:
    	return null
    else:
    	path = []
    	while current.node != start:
    		path += current.connection
    		current = current.connection.getFromNode()
    		
    	return reverse(path)

C++版,一些功能只提供了方法接口没有具体实现,但编译还是能过的。

#include<bits/stdc++.h>
using namespace std;
class Node{
public:
    int id;
    bool equal(Node node){
        return false;
    }
};
class Connection{
public:
    Node from;
    Node to;
    double w;
    Node getToNode(){return to;}
    double getCost(){return w;}
    Node getFromNode(){return from;}
};
struct NodeRecord{
    Node node;
    Connection connection;
    double cost;
    double costSoFar;
    double estimatedTotalCost;
};
class Graph{
public:
    vector<Connection> getConnections(NodeRecord noderecord){
        return vector<Connection>{};
    }
};
class Heuristic{
public:
    double estimate(Node node){
        return 0;
    }
};
class PathfindingList{
public:
    vector<NodeRecord> nodes;
    PathfindingList():nodes(vector<NodeRecord>()){}
    void push(NodeRecord node){
        nodes.push_back(node);
    }
    void pop(NodeRecord node){

    }
    bool empty(){
        return nodes.empty();
    }
    NodeRecord smallestElement(){
        return NodeRecord();
    }
    bool contains(Node node){
        return false;
    }
    NodeRecord find(Node node){
        return NodeRecord();
    }
};
vector<Connection> pathfindAStar(Graph graph,Node start,Node goal,Heuristic heuristic){

    NodeRecord startRecord = NodeRecord();
    startRecord.node = start;
    startRecord.connection = Connection();
    startRecord.costSoFar = 0;
    startRecord.estimatedTotalCost = heuristic.estimate(start);

    PathfindingList open;
    open.push(startRecord);
    PathfindingList closed;
    NodeRecord current;
    while(!open.empty()){
        current = open.smallestElement();
        if(current.node.equal(goal))break;
        vector<Connection> connnections = graph.getConnections(current);
        for(Connection connection : connnections){
            Node endNode = connection.getToNode();
            double endNodeCost = current.costSoFar + connection.getCost();
            NodeRecord endNodeRecord;
            double endNodeHeuristic=0;
            if(closed.contains(endNode)){
                endNodeRecord = closed.find(endNode);
                if(endNodeRecord.costSoFar <= endNodeCost)continue;
                closed.pop(endNodeRecord);
                endNodeHeuristic = endNodeRecord.cost - endNodeRecord.costSoFar;
            }else{
                endNodeRecord.node = endNode;
                endNodeHeuristic = heuristic.estimate(endNode);
            }
            endNodeRecord.cost = endNodeCost;
            endNodeRecord.connection = connection;
            endNodeRecord.estimatedTotalCost = endNodeCost + endNodeHeuristic;
            if(!open.contains(endNode)){
                open.push(endNodeRecord);
            }
        }
        open.pop(current);
        closed.push(current);
    }
    if(current.node.equal(goal))return vector<Connection>();
    else{
        vector<Connection> path=vector<Connection>();
        while(!current.node.equal(start)){
            path.push_back(current.connection);
            current = closed.find(current.connection.getFromNode());
        }
        reverse(path.begin(),path.end());
        return path;
    }
}
posted @ 2022-09-27 14:47  游子墨  阅读(376)  评论(0)    收藏  举报