A星算法(A*/A Star)

A星算法的前世今生 :

一、广度优先搜索(Breadth-first search (BFS))
    BFS是一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。它并不考虑结果的可能位址,彻底地搜索整张图,直到找到结果为止。

    算法逻辑:
        * 初始化open_list和close_list;
        * 将起点加入open_list中;
        * 如果open_list不为空,则从open_list中选取第一个节点n:
            * 如果节点n为终点,则:
                * 从终点开始逐步追踪parent节点,一直达到起点;
                * 返回找到的结果路径,算法结束;
            * 如果节点n不是终点,则:
                * 将节点n从open_list中删除,并加入close_list中;
                * 遍历节点n所有的邻近节点:
                    * 如果邻近节点m不在close_list/open_list中,则:
                        * 设置节点m的parent为节点n
                        * 计算节点m的优先级
                        * 将节点m加入open_list中
                    * 否则:
                        * 跳过,选取下一个邻近节点
                        
    缺点 :
    1、 时间复杂度是:T(n) = O(n^2),效率底下
    2、每个顶点之间没有权值,无法定义优先级,不能找到最优路线。比如遇到水域需要绕过行走,在宽度算法里面无法涉及。

二、Dijkstra的算法【迪杰斯特拉算法】
    给每个顶点添加一个移动代价,从起始位置跟踪总移动代价。如果位置的新路径比先前的最佳路径更好,我们将添加它,规划到新的路线中。

    算法逻辑:
        * 初始化open_list和close_list,每个格子的price,普通=1,高地=5;
        * 将始点S放入open_list,设置S.cost=0;
        * 如果open_list不为空,则从open_list中选取cost最小的节点n:
            * 如果节点n为终点,则:
                * 从终点开始逐步追踪parent节点,一直达到起点;
                * 返回找到的结果路径,算法结束;
            * 如果节点n不是终点,则:
                * 将节点n从open_list中删除,并加入close_list中;
                * 遍历节点n所有的邻近节点:
                    * 如果邻近节点m不在close_list/open_list中,则:
                        * 设置节点m的parent为节点n
                        * 计算起点S到节点m的cost,m.cost=n.cost+m.price
                        * 将节点m加入open_list中
                    * 否则:
                        * 跳过,选取下一个邻近节点
                        
    缺点 :
    1、时间复杂度是:T(n) = O(V^2),其中V为顶点个数。效率上并不高
    2、目标查找不具有方向性

三、贪婪最佳优先搜索(Greedy Best First Search)
    它是贪心算法,基于目标去搜索,而不是完全搜索;它的路径可能不是最优和最短的,但障碍物最少的时候,他的速度却足够的快。

    在Dijkstra算法中,优先队列采用的是,每个顶点到起始顶点的预估值来进行排序;
    在贪婪最佳优先搜索中,我们采用每个顶点到目标顶点的距离进行排序。

    算法逻辑:
        * 初始化open_list和close_list;
        * 将始点S放入open_list,设置S.cost=0,cost为该到目标点的曼哈顿距离;
        * 如果open_list不为空,则从open_list中选取cost最小的节点n:
            * 如果节点n为终点,则:
                * 从终点开始逐步追踪parent节点,一直达到起点;
                * 返回找到的结果路径,算法结束;
            * 如果节点n不是终点,则:
                * 将节点n从open_list中删除,并加入close_list中;
                * 遍历节点n所有的邻近节点:
                    * 如果邻近节点m不在close_list/open_list中,则:
                        * 设置节点m的parent为节点n
                        * 计算m到终点的曼哈顿距离cost
                        * 将节点m加入open_list中
                    * 否则:
                        * 跳过,选取下一个邻近节点
                        
    每个顶点到目标顶点的距离这个距离有多种方式可以计算:
        一、对角线距离【允许对角运动】 有下面这3种表示方法
        ①return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)
        ②return D * max(dx, dy) +(D2 - D) * min(dx, dy)
        ③Patrick Lester if(dx > dy) (D * (dx - dy) + D2 * dy) else (D * (dy - dx) + D2 * dx)

        二、曼哈顿距离【不允许对角】
        return abs(a.x - b.x) + abs(a.y - b.y)

        三、欧几里得距离
        return D * sqrt(dx * dx + dy *dy)
        不要用平方根,这样做会靠近g(n)的极端情况而不再计算任何东西,A*退化成BFS:

    缺点 :
    1、路径不是最短路径,只能是较优

A星算法
    在地图中寻找一个顶点到另一个顶点的最接近的路径,它优先考虑可能更接近目标的路径。如果是希望找到所有位置的路径可以使用[广度优先搜索]或者[Dijkstra算法]

    它吸取了 Dijkstra 算法中为每个边长设置权值,不停的计算每个顶点到起始顶点的距离(G),以获得最短路线;
    同时也汲取贪婪最佳优先搜索算法中不断向目标前进优势,并持续计算每个顶点到目标顶点的距离(Heuristic distance),以引导搜索队列不断想目标逼近,从而搜索更少的顶点,保持寻路的高效。

    公式 :
        ①在明确地算出了顶点到起始顶点的距离(G)和顶点到目标顶点的距离(H),
        ②我们只要在选择走哪个格子的时候,选择G+H的值最小的格子,这个值暂且命名为F,F = G + H,该值代表了在当前路线下选择走该方块的代价。
        
    A星算法还需要用到两个列表:
        开放列表- 用于记录所有可考虑选择的格子
        封闭列表- 用于记录所有不再考虑的格子
        
A星算法逻辑:
* 初始化open_list和close_list;
* 将起点加入open_list中,并设置优先级为0(优先级最高);
* 如果open_list不为空,则从open_list中选取优先级最高的节点n:
    * 如果节点n为终点,则:
        * 从终点开始逐步追踪parent节点,一直达到起点;
        * 返回找到的结果路径,算法结束;
    * 如果节点n不是终点,则:
        * 将节点n从open_list中删除,并加入close_list中;
        * 遍历节点n所有的邻近节点:
            * 如果邻近节点m在close_list中,则:
                * 跳过,选取下一个邻近节点
            * 如果m不在open_list中:
                * 设置节点m的parent为节点n
                * 计算节点m的优先级F=G+H
                * 将节点m加入open_list中
            * 如果m已在open_list中:
                * 重新计算m.g, int new_g=n.g+m.price;
                * 如果new_g < old_g :
                    * 设置节点m的parent为节点n
                    * 更新m.g和m.f
                * 否则:
                    * 跳过,选取下一个邻近节点
                        
    A*算法优化
        1、open_list: 查找算法、排序算法、二叉堆...
        2、根据路线选择H函数:     
            曼哈顿距离(Manhattan distance):只允许朝上下左右四个方向移动
            对角线距离: 允许朝八个方向移动
            欧几里得距离(Euclidean distance):允许朝任何方向移动
        3、采用布兰森汉姆算法预先判断两点是否可以直接通行,可通行就直接返回两点的直线路径,不可直接通行再采用A星算法寻路,提高寻路效率;
        4、A星算法得出寻路路径后,可采用弗洛伊德算法对路径进行平滑处理,使人物走动更为自然
        5、设计两个或者更多寻路系统以便使用在不同场合,取决于路径的长度。这也正是专业人士的做法,用大的区域计算长的路径,然后在接近目标的时候切换到使用小格子/区域的精细寻路。
        6. 从起点和终点同时开始找,双向A*

总结与展望:
    总结:
        BFS是盲目搜索,一直找邻居,直到找到目标;
        迪杰斯特拉算法是基于代价的,算起点到当前点代价最小的;
        贪婪优先算法是目标导向搜索,算当前点到目标代价最小的;        
        A星是结合迪杰斯特拉算法和贪婪优先算法的寻路,维护2个列表,开放和封闭列表,每次寻路的时候,从开放列表找出一个总代价最小的节点,如果不是终点,就算出起点到当前位置的移动代价G和当前位置到终点的移动代价H,计算出总代价F,然后加入封闭列表,并把这个节点所有的邻居都遍历一遍,计算总代价,加入开放列表,然后循环遍历,直到找到终点.
    展望:
        两层A星算法、双向A星、B星算法、双向B星、D星算法、JPS寻路算法

你可能感兴趣的:(算法,算法)