算法系列——A*算法

本系列旨在用简单的人话讲解算法,尽可能避免晦涩的定义,读者可以短时间内理解算法原理及应用细节。我在努力!

本篇文章编程语言为Python,供参考。

 A*算法

一种静态路网中求解最短路径最有效的直接搜索方法。(百度百科)

算法基本思路:创建两个数组分别记录待访问、已访问的结点,先将起始点放入待访问的数组,每次从待访问数组中选取F值最小的一个结点,然后将其上下左右四边中有效的结点放入待访问数组(有效条件:不出界、无障碍、未访问),不断重复以上操作,直到终点出现在待访问数组中(存在最短路径)或待排序数组为空(无法到达)为止。

 

 

 附全部源码:

brickList = [
    [0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
    [0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1],
    [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0],
    [0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0],
    [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0],
    [1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1],
    [0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0],
    [1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0],
    [0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1],
    [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0],
    [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
    [0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0],
    [1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1],
    [0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0],
]

#分别求当前迷宫的宽度及高度
w_brilist = len(brickList[0])
h_brilist = len(brickList)

zongzipos = (9,4)

class Grid():
    def __init__(self, x, y, dest=None, parent=None):
        #当前点的横纵坐标
        self.x = x
        self.y = y
        #目标结点(用于计算H值)
        self.dest = dest
        #用于记录当前结点的前驱结点(输出路径用)
        self.parent = parent
        if dest is not None:
            #G值为从起始点到当前点的距离
            self.g = self.parent.g + 1 if self.parent is not None else 1
            #H值为从当前点到终点的曼哈顿距离(不考虑障碍)
            self.h = abs(dest.x - self.x) + abs(dest.y - self.y)
            #F值为从起始点经过当前点到终点的距离
            self.f = self.g + self.h
        

    def get_valid_neighbors(self, open_list, close_list):
        #从上下左右四个方向判断邻居结点是否有效
        a = [(1,0), (-1,0), (0,1), (0,-1)]
        #用于保存有效的邻居结点
        res = []
        #逐个判断四边的邻居结点是否有效
        for i in a:
            #创建并判断邻居结点是否有效,有效保存
            tmp = Grid(self.x+i[0], self.y+i[1], self.dest, self)
            if tmp.is_valid(open_list, close_list):
                res.append(tmp)

        return res

    def is_valid(self, open_list, close_list):
        #出界
        if not (0 <= self.x < w_brilist and 0 <= self.y < h_brilist):
            return False
        
        #遇障碍物
        if brickList[self.x][self.y] != 0:
            return False

        #是否已出现过
        for i in open_list + close_list:
            if self.x == i.x and self.y == i.y:
                return False

        return True

    def is_dest(self):
        #判断是否为终点结点
        return self.x == self.dest.x and self.y == self.dest.y


def a_star_algorithm(src, dest):
    #初始化待访问及已访问列表
    open_list = [src]
    close_list = []

    #每次选取F值最小的一个结点,将他所有有效邻居加入列表,直到列表为空或出现终点为止。
    while open_list != []:
        #获取f值最小节点
        open_list.sort(key=lambda x: x.f)
        now = open_list.pop(0)
        close_list.append(now)
        #向待访问列表中加入当前结点所有有效邻居结点
        open_list.extend(now.get_valid_neighbors(open_list, close_list))

        #判断终点是否出现在待访问列表
        for i in open_list:
            if i.is_dest():
                return i

    return None

def get_path(dest):
    path = []
    while dest is not None:
        path.append((dest.x,dest.y))
        dest = dest.parent

    return path[::-1]
    

dest = Grid(*zongzipos)
src = Grid(0, 0, dest, None) 

c = a_star_algorithm(src, dest)

path = get_path(c)
print(path)

成果演示视频:

(为演示清楚,用pygame做了个图像版)

 参考资料:《漫画算法:小灰的算法之旅(Python篇)》

 

后记:很有意思的一个算法,尤其是能用pygame库展示出来看效果比直接看一串坐标清楚地多。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值