A*算法的理解与简单实现
基本定义
一种寻路算法,特点是:启发式的,效率高,基本思路比较简单。
用途
寻路。在指定的地图上,考虑到地图上的移动代价,找到最优的路径。
核心概念
开表,闭表,估值函数。
开表
开表,记录了当前需要处理的地图上的点。
1什么点会加入开表?
1.1 当一个点是起始点时,可以加入;
1.2 当一个点是起始点的邻接点,且不再闭表里时,可以进入开表;
2什么点会离开开表?
2.1开表中的点会按照f(n)进行升序排序,得到最小值的一个点被最先处理;当一个点已经处理后,会离开开表,加入闭表。
闭表
闭表,记录了当前已经处理的地图上的点。
1什么点会加入闭表?
1.1当一个点已经处理后,会加入闭表;
2什么点会离开闭表?
不会有点离开闭表。
估值函数
估值函数,估算了当前点处于最优路径上的代价。
估值函数f(n) = g(n) + h(n),其中g(n)表示由起点到当前点的代价;h(n)表示由当前点到终点的代价。A*算法的最核心部分也就是这个估值函数的设计。
在我的实现中,我用简单的几何距离作为估值函数的实现。
算法描述
1将起点加入开表
2开表里如果为空,算法退出;否则,取出f(n)最小的点作为最优路径上的点;
3针对当前处理的点,计算邻接点,如果邻接点不在闭表,且不在开表,加入开表
4重复2,3步骤直到退出
示例实现
1 #coding=utf8 2 """ 3 a* algorithm 4 """ 5 import math 6 7 AB_MAP = [ 8 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 9 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 10 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 11 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 12 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 13 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 14 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 15 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 16 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 17 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 18 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 19 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 20 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 21 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 22 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 23 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 24 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 25 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 26 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 27 [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,], 28 ] 29 POS_UP = 1 30 POS_LEFT = 2 31 POS_DOWN = 3 32 POS_RIGHT = 4 33 34 35 def mod_map(m_map, pos_x, pos_y, val): 36 """ 37 修改地图的某个点位的值 38 """ 39 m_map[pos_x][pos_y] = val 40 41 42 def print_map(m_map): 43 """ 44 打印地图 45 """ 46 rows = len(m_map) 47 for i in range(0, rows - 1): 48 cols = len(m_map[i]) 49 for j in range(0, cols - 1): 50 print str(m_map[i][j]) + "\t", 51 j = j + 1 52 print 53 i = i + 1 54 55 56 class Node(object): 57 """ 58 记录一个节点的信息 59 """ 60 def __init__(self, x, y, h_n=0, g_n=0): 61 self.pos_x = x 62 self.pos_y = y 63 self.parent = None 64 self.h_n = h_n 65 self.g_n = g_n 66 self.f_n = self.h_n + self.g_n 67 68 def update_h_n(self, target): 69 """ 70 计算h(n) 71 """ 72 self.h_n = int(math.sqrt((target.pos_x - self.pos_x)**2 + (target.pos_y - self.pos_y)**2)) 73 return self.h_n 74 75 def update_g_n(self, source): 76 """ 77 计算g(n) 78 """ 79 self.g_n = int(math.sqrt((source.pos_x - self.pos_x)**2 + (source.pos_y - self.pos_y)**2)) 80 return self.g_n 81 82 def update_f_n(self, source, target): 83 """ 84 计算f(n) 85 """ 86 self.f_n = self.update_g_n(source) + self.update_h_n(target) 87 return self.f_n 88 89 def update_parent(self, par): 90 """ 91 更新父节点 92 """ 93 self.parent = par 94 95 def get_adj_node(self, flag, source, target): 96 """ 97 计算邻近的节点 98 """ 99 if flag == POS_UP: 100 cur_node = Node(self.pos_x, self.pos_y - 1) 101 cur_node.update_f_n(source, target) 102 cur_node.parent = self 103 return cur_node 104 elif flag == POS_LEFT: 105 cur_node = Node(self.pos_x - 1, self.pos_y) 106 cur_node.update_f_n(source, target) 107 cur_node.parent = self 108 return cur_node 109 elif flag == POS_DOWN: 110 cur_node = Node(self.pos_x, self.pos_y + 1) 111 cur_node.update_f_n(source, target) 112 cur_node.parent = self 113 return cur_node 114 elif flag == POS_RIGHT: 115 cur_node = Node(self.pos_x + 1, self.pos_y) 116 cur_node.update_f_n(source, target) 117 cur_node.parent = self 118 return cur_node 119 else: 120 return None 121 122 123 def node_addible(node, open_list, close_list): 124 """ 125 判断一个点是否在open和close表 126 """ 127 index = str(node.pos_x) + '_' + str(node.pos_y) 128 if index not in open_list and index not in close_list: 129 open_list[index] = node 130 131 132 def reach_end(node, target): 133 """ 134 判断一个点是否到达终点 135 """ 136 if node and target and node.pos_x == target.pos_x and node.pos_y == target.pos_y: 137 return True 138 else: 139 return False 140 141 142 def handle_reach_end(node, mmap, modval, print_path=False): 143 """ 144 当一个点到达终点时的处理方法 145 """ 146 if node and mmap: 147 while node: 148 if print_path: 149 print "x: %s, y: %s" % (node.pos_x, node.pos_y) 150 mod_map(mmap, node.pos_x, node.pos_y, modval) 151 node = node.parent 152 153 def main(source, target, open_list, close_list, mmap): 154 """ 155 主函数 156 """ 157 open_list[str(source.pos_x) + '_' + str(source.pos_y)] = source 158 while open_list: 159 tmp_dict = sorted(open_list.iteritems(), key=lambda d: d[1].f_n) 160 first_key = tmp_dict[0][0] 161 first_node = open_list[first_key] 162 del open_list[first_key] 163 164 up_node = first_node.get_adj_node(POS_UP, source, target) 165 if reach_end(up_node, target): 166 handle_reach_end(up_node, mmap, 2) 167 break 168 169 left_node = first_node.get_adj_node(POS_LEFT, source, target) 170 if reach_end(left_node, target): 171 handle_reach_end(left_node, mmap, 2) 172 break 173 174 down_node = first_node.get_adj_node(POS_DOWN, source, target) 175 if reach_end(down_node, target): 176 handle_reach_end(down_node, mmap, 2) 177 break 178 179 right_node = first_node.get_adj_node(POS_RIGHT, source, target) 180 if reach_end(right_node, target): 181 handle_reach_end(right_node, mmap, 2) 182 break 183 184 if first_key not in close_list: 185 close_list[first_key] = first_node 186 187 node_addible(up_node, open_list, close_list) 188 node_addible(down_node, open_list, close_list) 189 node_addible(left_node, open_list, close_list) 190 node_addible(right_node, open_list, close_list) 191 192 193 if __name__ == '__main__': 194 print "******************************* before *******************************" 195 print_map(AB_MAP) 196 OPEN_LIST = {} 197 CLOSE_LIST = {} 198 199 SOURCE = Node(3, 4) 200 TARGET = Node(13, 9) 201 main(SOURCE, TARGET, OPEN_LIST, CLOSE_LIST, AB_MAP) 202 203 print "******************************** after ********************************" 204 mod_map(AB_MAP, SOURCE.pos_x, SOURCE.pos_y, 0) 205 mod_map(AB_MAP, TARGET.pos_x, TARGET.pos_y, 0) 206 print_map(AB_MAP)
参考文章
http://www.cnblogs.com/technology/archive/2011/05/26/2058842.html
http://blog.sciencenet.cn/blog-5422-538894.html
https://segmentfault.com/a/1190000004462060
http://blog.csdn.net/v_JULY_v/article/details/6093380
http://blog.csdn.net/zhuangxiaobin/article/details/38755447
http://www.cnblogs.com/tongy0/p/5671545.html