基本定义

一种寻路算法,特点是:启发式的,效率高,基本思路比较简单。

用途

寻路。在指定的地图上,考虑到地图上的移动代价,找到最优的路径。

核心概念

开表,闭表,估值函数。

开表

开表,记录了当前需要处理的地图上的点。

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步骤直到退出

示例实现

 #coding=utf8
"""
a* algorithm
"""
import math AB_MAP = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,],
]
POS_UP = 1
POS_LEFT = 2
POS_DOWN = 3
POS_RIGHT = 4 def mod_map(m_map, pos_x, pos_y, val):
"""
修改地图的某个点位的值
"""
m_map[pos_x][pos_y] = val def print_map(m_map):
"""
打印地图
"""
rows = len(m_map)
for i in range(0, rows - 1):
cols = len(m_map[i])
for j in range(0, cols - 1):
print str(m_map[i][j]) + "\t",
j = j + 1
print
i = i + 1 class Node(object):
"""
记录一个节点的信息
"""
def __init__(self, x, y, h_n=0, g_n=0):
self.pos_x = x
self.pos_y = y
self.parent = None
self.h_n = h_n
self.g_n = g_n
self.f_n = self.h_n + self.g_n def update_h_n(self, target):
"""
计算h(n)
"""
self.h_n = int(math.sqrt((target.pos_x - self.pos_x)**2 + (target.pos_y - self.pos_y)**2))
return self.h_n def update_g_n(self, source):
"""
计算g(n)
"""
self.g_n = int(math.sqrt((source.pos_x - self.pos_x)**2 + (source.pos_y - self.pos_y)**2))
return self.g_n def update_f_n(self, source, target):
"""
计算f(n)
"""
self.f_n = self.update_g_n(source) + self.update_h_n(target)
return self.f_n def update_parent(self, par):
"""
更新父节点
"""
self.parent = par def get_adj_node(self, flag, source, target):
"""
计算邻近的节点
"""
if flag == POS_UP:
cur_node = Node(self.pos_x, self.pos_y - 1)
cur_node.update_f_n(source, target)
cur_node.parent = self
return cur_node
elif flag == POS_LEFT:
cur_node = Node(self.pos_x - 1, self.pos_y)
cur_node.update_f_n(source, target)
cur_node.parent = self
return cur_node
elif flag == POS_DOWN:
cur_node = Node(self.pos_x, self.pos_y + 1)
cur_node.update_f_n(source, target)
cur_node.parent = self
return cur_node
elif flag == POS_RIGHT:
cur_node = Node(self.pos_x + 1, self.pos_y)
cur_node.update_f_n(source, target)
cur_node.parent = self
return cur_node
else:
return None def node_addible(node, open_list, close_list):
"""
判断一个点是否在open和close表
"""
index = str(node.pos_x) + '_' + str(node.pos_y)
if index not in open_list and index not in close_list:
open_list[index] = node def reach_end(node, target):
"""
判断一个点是否到达终点
"""
if node and target and node.pos_x == target.pos_x and node.pos_y == target.pos_y:
return True
else:
return False def handle_reach_end(node, mmap, modval, print_path=False):
"""
当一个点到达终点时的处理方法
"""
if node and mmap:
while node:
if print_path:
print "x: %s, y: %s" % (node.pos_x, node.pos_y)
mod_map(mmap, node.pos_x, node.pos_y, modval)
node = node.parent def main(source, target, open_list, close_list, mmap):
"""
主函数
"""
open_list[str(source.pos_x) + '_' + str(source.pos_y)] = source
while open_list:
tmp_dict = sorted(open_list.iteritems(), key=lambda d: d[1].f_n)
first_key = tmp_dict[0][0]
first_node = open_list[first_key]
del open_list[first_key] up_node = first_node.get_adj_node(POS_UP, source, target)
if reach_end(up_node, target):
handle_reach_end(up_node, mmap, 2)
break left_node = first_node.get_adj_node(POS_LEFT, source, target)
if reach_end(left_node, target):
handle_reach_end(left_node, mmap, 2)
break down_node = first_node.get_adj_node(POS_DOWN, source, target)
if reach_end(down_node, target):
handle_reach_end(down_node, mmap, 2)
break right_node = first_node.get_adj_node(POS_RIGHT, source, target)
if reach_end(right_node, target):
handle_reach_end(right_node, mmap, 2)
break if first_key not in close_list:
close_list[first_key] = first_node node_addible(up_node, open_list, close_list)
node_addible(down_node, open_list, close_list)
node_addible(left_node, open_list, close_list)
node_addible(right_node, open_list, close_list) if __name__ == '__main__':
print "******************************* before *******************************"
print_map(AB_MAP)
OPEN_LIST = {}
CLOSE_LIST = {} SOURCE = Node(3, 4)
TARGET = Node(13, 9)
main(SOURCE, TARGET, OPEN_LIST, CLOSE_LIST, AB_MAP) print "******************************** after ********************************"
mod_map(AB_MAP, SOURCE.pos_x, SOURCE.pos_y, 0)
mod_map(AB_MAP, TARGET.pos_x, TARGET.pos_y, 0)
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

A*算法的理解与简单实现的更多相关文章

  1. SDUT OJ 数据结构实验之串一:KMP简单应用 && 浅谈对看毛片算法的理解

    数据结构实验之串一:KMP简单应用 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descr ...

  2. 量化交易中VWAP/TWAP算法的基本原理和简单源码实现(C++和python)(转)

    量化交易中VWAP/TWAP算法的基本原理和简单源码实现(C++和python) 原文地址:http://blog.csdn.net/u012234115/article/details/728300 ...

  3. Vue中diff算法的理解

    Vue中diff算法的理解 diff算法用来计算出Virtual DOM中改变的部分,然后针对该部分进行DOM操作,而不用重新渲染整个页面,渲染整个DOM结构的过程中开销是很大的,需要浏览器对DOM结 ...

  4. React中diff算法的理解

    React中diff算法的理解 diff算法用来计算出Virtual DOM中改变的部分,然后针对该部分进行DOM操作,而不用重新渲染整个页面,渲染整个DOM结构的过程中开销是很大的,需要浏览器对DO ...

  5. kNN算法python实现和简单数字识别

    kNN算法 算法优缺点: 优点:精度高.对异常值不敏感.无输入数据假定 缺点:时间复杂度和空间复杂度都很高 适用数据范围:数值型和标称型 算法的思路: KNN算法(全称K最近邻算法),算法的思想很简单 ...

  6. 1102: 零起点学算法09——继续练习简单的输入和计算(a-b)

    1102: 零起点学算法09--继续练习简单的输入和计算(a-b) Time Limit: 1 Sec  Memory Limit: 520 MB   64bit IO Format: %lldSub ...

  7. openCV中直方图均衡化算法的理解

    直方图均衡化就是调整灰度直方图的分布,即将原图中的灰度值映射为一个新的值.映射的结果直观表现是灰度图的分布变得均匀,从0到255都有分布,不像原图那样集中.图像上的表现就是对比度变大,亮的更亮,暗的更 ...

  8. 【repost】让你一句话理解闭包(简单易懂)

    接触javascript很久了,每次理解闭包都似是而非,最近在找Web前端的工作,所以需要把基础夯实一下. 本文是参照了joy_lee的博客 闭包 在她这篇博客的基础上以批注的形式力争把我的理解阐述出 ...

  9. Map集合遍历的四种方式理解和简单使用-----不能for循环遍历

    Map集合遍历的四种方式理解和简单使用   ~Map集合是键值对形式存储值的,所以遍历Map集合无非就是获取键和值,根据实际需求,进行获取键和值 1:无非就是通过map.keySet()获取到值,然后 ...

随机推荐

  1. 如何用photoshop把一张图片分割成几张图片呢?

    今天情人节,祝大家节日快乐!朋友发来一张照片,我发现这张照片是几张照片组合起来的,是不是感觉每一张都是萌萌哒呢?为了体现单张的独特性,现在我要把它切分成单张,使用Photoshop CS5该怎么弄呢? ...

  2. unity插件开发——AssetDatabase

    AssetDatebase也是一个静态类,他的作用是管理整个工程的所有文件(一般成为“资产”).直观地说就是管理整个project窗口中的所有内容,比如,你可以增加.删除.修改文件等等. 这里有几个常 ...

  3. freemarker导出word文档——WordXML格式解析

    前不久,公司一个项目需要实现导出文档的功能,之前是一个同事在做,做了3个星期,终于完成了,但是在项目上线之后却发现导出的文档有问题,此时,这个同事已经离职,我自然成为接班者,要把导出功能实现,但是我看 ...

  4. 重温Javascript(一)

    工作中要用到JavaScript,一组复习笔记. 一些看法 1. 想想JavaScript目前最常用的宿主环境,浏览器或者服务端V8,都是单线程,所以不用过多的考虑并发的问题,如果是协程来实现异步的方 ...

  5. Struts2的类型转换(上)

    传统的类型转换.(略) Struts2中提供了内置的基本的类型转换器,可以实现基本类型的自动转换,包括: Integer, Float, Double, Decimal Date and Dateti ...

  6. 性能测试分享:MYSQL死锁

    poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478,咨询电话010-845052 ...

  7. DCN路由操作

    offset */interface in/out access-list/prefix-list <1-16>                 // 修改路由偏移量   RIP偏移列表 ...

  8. windows server 定期备份数据库脚本

    将以下文件保存为.bat脚本,在计划任务中添加定时任务运行此脚本即可.脚本中的备份目录,数据库目录和压缩文件目录请自行修改. @echo off rem 当前路径切换到备份数据库目录 cd D:\wa ...

  9. 第1课 - 学习Lua的意义

    学习Lua的意义 1.Lua简介             (1) 1993年.巴西 (2) 小巧精致的脚本语言,大小只有200K (3) 用标准C语言写成,能够在所有的平台上编译运行 (4) 发明的目 ...

  10. 使用Docker分分钟启动常用应用

    前言 Docker是目前比较火的一个概念,同时也是微服务中比较关键的一个容器化技术.但是,单从理论上好难看出Docker的优势,因此,我希望在这篇文章中提供一些Docker的使用示例,希望从实际应用上 ...