转载链接
路径规划之 A 算法*
https://developer.aliyun.com/article/685477
https://www.redblobgames.com/pathfinding/a-star/introduction.html
基于python语言,实现A*算法对最短路问题(Shortest Path Problem)进行求解。
1. 适用场景
- 无负环网络
- 起点与终点间至少存在一条可行路径
2. 测试网络
这里以Tempe ASU网络为测试数据集,网络如下图所示,可通过osm2gmns工具包获取。
3. 代码实现
(1)定义数据结构
class Network():
def __init__(self):
self.source_node_id=None
self.sink_node_id=None
self.node_id_list=[]
self.node_x_coord={}
self.node_y_coord={}
self.node_neighbors={}
self.number_of_nodes=0
self.link_list=[]
self.link_cost={}
(2)读取csv网络文件
node.csv
link.csv
def read_data(node_file,link_file,net):
#读取node文件
with open(node_file) as f:
node_reader = csv.reader(f)
next(node_reader)
for row in node_reader:
net.node_id_list.append(int(row[0]))
net.node_x_coord[int(row[0])]=float(row[1])
net.node_y_coord[int(row[0])]=float(row[2])
net.node_neighbors[int(row[0])]=[]
#读取link文件
with open(link_file) as f:
link_reader=csv.reader(f)
next(link_reader)
for row in link_reader:
from_node_id=int(row[1])
to_node_id=int(row[2])
cost=float(row[3])
net.node_neighbors[from_node_id].append(to_node_id)
net.link_list.append([from_node_id,to_node_id])
net.link_cost[from_node_id,to_node_id]=cost
net.number_of_nodes=len(net.node_id_list)
(3)评估函数
def evaluate_remaining_distance(current,net):
return abs(net.node_x_coord[current]-net.node_x_coord[net.sink_node_id])\
+abs(net.node_y_coord[current]-net.node_y_coord[net.sink_node_id])
(4)最短路径可视化函数
def show_shortest_path(net,path_node_id_list):
for from_node_id,to_node_id in net.link_list:
x_coords=[net.node_x_coord[from_node_id],net.node_x_coord[to_node_id]]
y_coords=[net.node_y_coord[from_node_id],net.node_y_coord[to_node_id]]
plt.plot(x_coords,y_coords,color='black',linewidth=0.5)
path_x_coord=[]
path_y_coord=[]
for node_id in path_node_id_list:
path_x_coord.append(net.node_x_coord[node_id])
path_y_coord.append(net.node_y_coord[node_id])
plt.plot(path_x_coord,path_y_coord,color='b')
plt.xlabel('x_coord')
plt.ylabel('y_coord')
plt.show()
(5)最短路搜索
def find_shortest_path(net):
frontier = PriorityQueue()
frontier.put((net.source_node_id,0))
came_from = {}
cost_so_far = {}
came_from[net.source_node_id] = None
cost_so_far[net.source_node_id] = 0
while not frontier.empty():
current=frontier.get()[0]
if current == net.sink_node_id:
break
for next_node in net.node_neighbors[current]:
new_cost = cost_so_far[current] + net.link_cost[current, next_node]
if next_node not in cost_so_far or new_cost < cost_so_far[next_node]:
cost_so_far[next_node] = new_cost
priority = new_cost + evaluate_remaining_distance(next_node,net)
frontier.put((next_node,priority))
came_from[next_node] = current
path_node_id_list=[net.sink_node_id]
pre_node_id=came_from[net.sink_node_id]
path_cost=0
while pre_node_id!=net.source_node_id:
path_node_id_list.insert(0,pre_node_id)
path_cost+=net.link_cost[path_node_id_list[0],path_node_id_list[1]]
pre_node_id=came_from[pre_node_id]
path_node_id_list.insert(0,net.source_node_id)
path_cost += net.link_cost[path_node_id_list[0], path_node_id_list[1]]
path='-'.join( [ str(i) for i in path_node_id_list] )
print("the trave cost from node id=%s to node id=%s is: %s"%(net.source_node_id,net.sink_node_id,path_cost))
print("the shortest path from node id=%s to node id=%s is: %s"%(net.source_node_id,net.sink_node_id,path))
show_shortest_path(net,path_node_id_list)
(6)主函数
if __name__=='__main__':
net=Network()
net.source_node_id=4298
net.sink_node_id=169
read_data('./node.csv','./link.csv',net)
if net.source_node_id not in net.node_id_list:
print(" %s not found"%net.source_node_id)
sys.exit(0)
if net.sink_node_id not in net.node_id_list:
print(" %s not found"%net.sink_node_id)
sys.exit(0)
find_shortest_path(net)
(7)求解结果
(8)样例数据集代码文件
https://github.com/PariseC/Shortest_Path_Algorithm/tree/master/A%20star