关于A* 算法

初识A*算法


写这篇文章的初衷是应一个网友的要求,当然我也发现现在有关人工智能的中文
站点实在太少,我在这里 抛砖引玉,希望大家都来热心的参与。

还是说正题,我先拿A*算法开刀,是因为A*在游戏中有它很典型的用法,是人工
智能在游戏中的代表。

A*算法在人工智能中是一种典型的启发式搜索算法,为了说清楚A*算法,我看还
是先说说何谓启发式算法。

一、何谓启发式搜索算法:

在说它之前先提提状态空间搜索。状态空间搜索,如果按专业点的说法就是将问
题求解过程表现为从 初始状态到目标状态寻找这个路径的过程。通俗点说,就是
在解一个问题时,找到一条解题的过程可以从 求解的开始到问题的结果(好象并
不通俗哦)。由于求解问题的过程中分枝有很多,主要是求解过程中求 解条件的
不确定性,不完备性造成的,使得求解的路径很多这就构成了一个图,我们说这
个图就是状态空 间。问题的求解实际上就是在这个图中找到一条路径可以从开始
到结果。这个寻找的过程就是状态空间搜索。

常用的状态空间搜索有深度优先和广度优先。广度优先是从初始状态一层一层向
下找,直到找到目标 为止。深度优先是按照一定的顺序前查找完一个分支,再查
找另一个分支,以至找到目标为止。这两种算 法在数据结构书中都有描述,可以
参看这些书得到更详细的解释。

前面说的广度和深度优先搜索有一个很大的缺陷就是他们都是在一个给定的状态
空间中穷举。这在状 态空间不大的情况下是很合适的算法,可是当状态空间十分
大,且不预测的情况下就不可取了。他的效率 实在太低,甚至不可完成。在这里
就要用到启发式搜索了。

启发式搜索就是在状态空间中的搜索对每一个搜索的位置进行评估,得到最好的
位置,再从这个位置 进行搜索直到目标。这样可以省略大量无畏的搜索路径,提
到了效率。在启发式搜索中,对位置的估价是 十分重要的。采用了不同的估价可
以有不同的效果。我们先看看估价是如何表示的。

启发中的估价是用估价函数表示的,如:

f(n) = g(n) + h(n)

其中f(n) 是节点n的估价函数,g(n)实在状态空间中从初始节点到n节点的实际代
价,h(n)是从n到目 标节点最佳路径的估计代价。在这里主要是h(n)体现了搜索
的启发信息,因为g(n)是已知的。如果说详细 点,g(n)代表了搜索的广度的优先
趋势。但是当h(n) >> g(n)时,可以省略g(n),而提高效率。这些就深了, 不懂
也不影响啦!我们继续看看何谓A*算法。

二、初识A*算法:

启发式搜索其实有很多的算法,比如:局部择优搜索法、最好优先搜索法等等。
当然A*也是。这些算法 都使用了启发函数,但在具体的选取最佳搜索节点时的策
略不同。象局部择优搜索法,就是在搜索的过程中 选取“最佳节点”后舍弃其他
的兄弟节点,父亲节点,而一直得搜索下去。这种搜索的结果很明显,由于舍 弃
了其他的节点,可能也把最好的节点都舍弃了,因为求解的最佳节点只是在该阶
段的最佳并不一定是全局 的最佳。最好优先就聪明多了,他在搜索时,便没有舍
弃节点(除非该节点是死节点),在每一步的估价中 都把当前的节点和以前的节
点的估价值比较得到一个“最佳的节点”。这样可以有效的防止“最佳节点”的
丢失。那么A*算法又是一种什么样的算法呢?其实A*算法也是一种最好优先的算
法。只不过要加上一些约束 条件罢了。由于在一些问题求解时,我们希望能够求
解出状态空间搜索的最短路径,也就是用最快的方法求 解问题,A*就是干这种事
情的!我们先下个定义,如果一个估价函数可以找出最短的路径,我们称之为可
采 纳性。A*算法是一个可采纳的最好优先算法。A*算法的估价函数克表示为:


f'(n) = g'(n) + h'(n)

这里,f'(n)是估价函数,g'(n)是起点到终点的最短路径值,h'(n)是n到目标的
最断路经的启发值。由 于这个f'(n)其实是无法预先知道的,所以我们用前面的
估价函数f(n)做近似。g(n)代替g'(n),但 g(n)>=g'(n) 才可(大多数情况下都
是满足的,可以不用考虑),h(n)代替h'(n),但h(n)<=h'(n)才可(这一点特别
的重 要)。可以证明应用这样的估价函数是可以找到最短路径的,也就是可采纳
的。我们说应用这种估价函数的 最好优先算法就是A*算法。哈!你懂了吗?肯定
没懂!接着看!

举一个例子,其实广度优先算法就是A*算法的特例。其中g(n)是节点所在的层数
,h(n)=0,这种h(n)肯 定小于h'(n),所以由前述可知广度优先算法是一种可采
纳的。实际也是。当然它是一种最臭的A*算法。

再说一个问题,就是有关h(n)启发函数的信息性。h(n)的信息性通俗点说其实就
是在估计一个节点的值 时的约束条件,如果信息越多或约束条件越多则排除的节
点就越多,估价函数越好或说这个算法越好。这就 是为什么广度优先算法的那么
臭的原因了,谁叫它的h(n)=0,一点启发信息都没有。但在游戏开发中由于实 时
性的问题,h(n)的信息越多,它的计算量就越大,耗费的时间就越多。就应该适
当的减小h(n)的信息,即 减小约束条件。但算法的准确性就差了,这里就有一个
平衡的问题。可难了,这就看你的了!

好了我的话也说得差不多了,我想你肯定是一头的雾水了,其实这是写给懂A*算
法的同志看的。哈哈! 你还是找一本人工智能的书仔细看看吧!我这几百字是不
足以将A*算法讲清楚的。只是起到抛砖引玉的作用 希望大家热情参与吗!

预知A*算法的应用,请看《深入A*算法》。

现在的位置是: 算法结构 | 游戏制作 > 深入A*算法

资料整理·中国程序员网站


   

深入A*算法----浅析A*算法在搜索最短路径中的应用


 
一、前言

在这里我将对A*算法的实际应用进行一定的探讨,并且举一个有关A*算法在最短
路径搜索 的例子。值得注意的是这里并不对A*的基本的

概念作介绍,如果你还对A*算法不清楚的话, 请看姊妹篇《初识A*算法》。

这里所举的例子是参考AMIT主页中的一个源程序,你可以在AMIT的站点上下载也
可以在我 的站点上下载。你使用这个源程序时,应该遵

守一定的公约。

二、A*算法的程序编写原理

我在《初识A*算法》中说过,A*算法是最好优先算法的一种。只是有一些约束条
件而已。 我们先来看看最好优先算法是如何编写的吧。

如图有如下的状态空间:(起始位置是A,目标位置是P,字母后的数字表示节点
的估价值)

搜索过程中设置两个表:OPEN和CLOSED。OPEN表保存了所有已生成而未考察的节
点,CLOSED 表中记录已访问过的节点。算法中有一步是

根据估价函数重排OPEN表。这样循环中的每一 步只考虑OPEN表中状态最好的节点
。具体搜索过程如下:


1)初始状态:
OPEN=[A5];CLOSED=[];
2)估算A5,取得搜有子节点,并放入OPEN表中;
OPEN=[B4,C4,D6];CLOSED=[A5]
3)估算B4,取得搜有子节点,并放入OPEN表中;
OPEN=[C4,E5,F5,D6];CLOSED=[B4,A5]
4)估算C4;取得搜有子节点,并放入OPEN表中;
OPEN=[H3,G4,E5,F5,D6];CLOSED=[C4,B4,A5]
5)估算H3,取得搜有子节点,并放入OPEN表中;
OPEN=[O2,P3,G4,E5,F5,D6];CLOSED=H3C4,B4,A5]
6)估算O2,取得搜有子节点,并放入OPEN表中;
OPEN=[P3,G4,E5,F5,D6];CLOSED=[O2,H3,C4,B4,A5]
7)估算P3,已得到解;

看了具体的过程,再看看伪程序吧。算法的伪程序如下:


Best_First_Search()
{
Open = [起始节点]; Closed = [];
while ( Open表非空 )
{
    从Open中取得一个节点X,并从OPEN表中删除。
    if (X是目标节点)
    {
求得路径PATH;返回路径PATH;
            }
    for (每一个X的子节点Y)
    {
if( Y不在OPEN表和CLOSE表中 )
{
   求Y的估价值;并将Y插入OPEN表中;//还没有排序
}
else
    if( Y在OPEN表中 )
    {
if( Y的估价值小于OPEN表的估价值 )
    更新OPEN表中的估价值;
    }
    else //Y在CLOSE表中
                    {
if( Y的估价值小于CLOSE表的估价值 )
{
    更新CLOSE表中的估价值;
    从CLOSE表中移出节点,并放入OPEN表中;
}
    }
        将X节点插入CLOSE表中;
        按照估价值将OPEN表中的节点排序;
             }//end for
}//end while
}//end func

啊!伪程序出来了,写一个源程序应该不是问题了,依葫芦画瓢就可以。A*算法
的程序与此 是一样的,只要注意估价函数中的g(n)的h(n)约束条件就可以了。不
清楚的可以看看《初识A*算法》。好了,我们可以进入另一个重要的话题,用A*
算法实现最短路径的搜索。在此之 前你最好认真的理解前面的算法。不清楚可以
找我。我的Email在文章尾。

三、用A*算法实现最短路径的搜索

在游戏设计中,经常要涉及到最短路径的搜索,现在一个比较好的方法就是用A*
算法进行设 计。他的好处我们就不用管了,反正就是好!^_*

注意下面所说的都是以 ClassAstar 这个程序为蓝本,你可以在这里下载这个程
序。这个程 序是一个完整的工程。里面带了一个EXE文件。可以先看看。

先复习一下,A*算法的核心是估价函数f(n),它包括g(n)和h(n)两部分。g(n) 是
已经走过的 代价,h(n)是n到目标的估计代价。在这个例子中g(n)表示在状态空
间从起始节点到 n节点的 深度,h(n)表示n节点所在地图的位置到目标位置的直
线距离。啊!一个是状态空间,一个是 实际的地图,不要搞错了。再详细点说,
有一个物体A,在地图上的坐标是(xa,ya),A所要到 达的目标b的坐标是(xb,yb)
。则开始搜索时,设置一个起始节点1,生成八个子节点2 - 9 因 为有八个方向
。如图:

仔细看看节点1、9、17的g(n)和h(n)是怎么计算的。现在应该知道了下面程序中
的f(n)是如何 计算的吧。开始讲解源程序了。其实这个程序是一个很典型的教科
书似的程序,也就是说只要 你看懂了上面的伪程序,这个程序是十分容易理解的
。不过他和上面的伪程序有一些的不同, 我在后面会提出来。

先看搜索主函数:


先看搜索主函数:

  

A*算法详解——by Sunway - 白杨 - 白杨void AstarPathfinder::FindPath(int sx, int sy, int dx, int  dy)
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨  
A*算法详解——by Sunway - 白杨 - 白杨
{
A*算法详解——by Sunway - 白杨 - 白杨    NODE 
*Node, *
BestNode;
A*算法详解——by Sunway - 白杨 - 白杨    
int
 TileNumDest;
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    
//得到目标位置,作判断用

A*算法详解——by Sunway - 白杨 - 白杨
    TileNumDest = TileNum(sx, sy);
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    
//生成Open和Closed表

A*算法详解——by Sunway - 白杨 - 白杨
    OPEN=( NODE* )calloc(1,sizeof( NODE ));
A*算法详解——by Sunway - 白杨 - 白杨    CLOSED
=( NODE* )calloc(1,sizeof
( NODE ));
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    
//生成起始节点,并放入Open表中

A*算法详解——by Sunway - 白杨 - 白杨
    Node=( NODE* )calloc(1,sizeof( NODE ));
A*算法详解——by Sunway - 白杨 - 白杨    Node
->= 0
;
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    
//这是计算h值

A*算法详解——by Sunway - 白杨 - 白杨
    Node->= (dx-sx)*(dx-sx) + (dy-sy)*(dy-sy); // should really use sqrt().
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    
//这是计算f值,即估价值

A*算法详解——by Sunway - 白杨 - 白杨
    Node->= Node->g+Node->h;
A*算法详解——by Sunway - 白杨 - 白杨    Node
->NodeNum =
 TileNum(dx, dy);
A*算法详解——by Sunway - 白杨 - 白杨    Node
->=
 dx;
A*算法详解——by Sunway - 白杨 - 白杨    Node
->=
 dy;
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    OPEN
->NextNode=Node; // make Open List point to first node

A*算法详解——by Sunway - 白杨 - 白杨
    for (;;)
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨    
A*算法详解——by Sunway - 白杨 - 白杨
{
A*算法详解——by Sunway - 白杨 - 白杨      
//从Open表中取得一个估价值最好的节点

A*算法详解——by Sunway - 白杨 - 白杨
      BestNode=ReturnBestNode();
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨      
//如果该节点是目标节点就退出

A*算法详解——by Sunway - 白杨 - 白杨
      if (BestNode->NodeNum == TileNumDest) // if we've found the end, break and finish
A*算法详解——by Sunway - 白杨 - 白杨
        break;
A*算法详解——by Sunway - 白杨 - 白杨      
//否则生成子节点

A*算法详解——by Sunway - 白杨 - 白杨
      GenerateSuccessors(BestNode,sx,sy);
A*算法详解——by Sunway - 白杨 - 白杨    }

A*算法详解——by Sunway - 白杨 - 白杨    PATH 
= BestNode;
A*算法详解——by Sunway - 白杨 - 白杨  }

A*算法详解——by Sunway - 白杨 - 白杨


  再看看生成子节点函数 GenerateSuccessors:

  

A*算法详解——by Sunway - 白杨 - 白杨void AstarPathfinder::GenerateSuccessors(NODE *BestNode, int dx, int  dy)
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨  
A*算法详解——by Sunway - 白杨 - 白杨
{
A*算法详解——by Sunway - 白杨 - 白杨    
int
 x, y;
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    
//
依次生成八个方向的子节点,简单!
A*算法详解——by Sunway - 白杨 - 白杨    
// Upper-Left

A*算法详解——by Sunway - 白杨 - 白杨
    if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y-TILESIZE) )
A*算法详解——by Sunway - 白杨 - 白杨      GenerateSucc(BestNode,x,y,dx,dy);
A*算法详解——by Sunway - 白杨 - 白杨    
// Upper

A*算法详解——by Sunway - 白杨 - 白杨
    if ( FreeTile(x=BestNode->x, y=BestNode->y-TILESIZE) )
A*算法详解——by Sunway - 白杨 - 白杨      GenerateSucc(BestNode,x,y,dx,dy);
A*算法详解——by Sunway - 白杨 - 白杨    
// Upper-Right

A*算法详解——by Sunway - 白杨 - 白杨
    if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y-TILESIZE) )
A*算法详解——by Sunway - 白杨 - 白杨      GenerateSucc(BestNode,x,y,dx,dy);
A*算法详解——by Sunway - 白杨 - 白杨    
// Right

A*算法详解——by Sunway - 白杨 - 白杨
    if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y) )
A*算法详解——by Sunway - 白杨 - 白杨      GenerateSucc(BestNode,x,y,dx,dy);
A*算法详解——by Sunway - 白杨 - 白杨    
// Lower-Right

A*算法详解——by Sunway - 白杨 - 白杨
    if ( FreeTile(x=BestNode->x+TILESIZE, y=BestNode->y+TILESIZE) )
A*算法详解——by Sunway - 白杨 - 白杨      GenerateSucc(BestNode,x,y,dx,dy);
A*算法详解——by Sunway - 白杨 - 白杨    
// Lower

A*算法详解——by Sunway - 白杨 - 白杨
    if ( FreeTile(x=BestNode->x, y=BestNode->y+TILESIZE) )
A*算法详解——by Sunway - 白杨 - 白杨      GenerateSucc(BestNode,x,y,dx,dy);
A*算法详解——by Sunway - 白杨 - 白杨    
// Lower-Left

A*算法详解——by Sunway - 白杨 - 白杨
    if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y+TILESIZE) )
A*算法详解——by Sunway - 白杨 - 白杨      GenerateSucc(BestNode,x,y,dx,dy);
A*算法详解——by Sunway - 白杨 - 白杨    
// Left

A*算法详解——by Sunway - 白杨 - 白杨
    if ( FreeTile(x=BestNode->x-TILESIZE, y=BestNode->y) )
A*算法详解——by Sunway - 白杨 - 白杨      GenerateSucc(BestNode,x,y,dx,dy);
A*算法详解——by Sunway - 白杨 - 白杨  }

A*算法详解——by Sunway - 白杨 - 白杨


  看看最重要的函数GenerateSucc:

  

A*算法详解——by Sunway - 白杨 - 白杨void AstarPathfinder::GenerateSucc(NODE *BestNode,int x, int y, int dx, int  dy)
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨  
A*算法详解——by Sunway - 白杨 - 白杨
{
A*算法详解——by Sunway - 白杨 - 白杨    
int g, TileNumS, c = 0
;
A*算法详解——by Sunway - 白杨 - 白杨    NODE 
*Old, *
Successor;
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    
//计算子节点的 g 值

A*算法详解——by Sunway - 白杨 - 白杨
    g = BestNode->g+1// g(Successor)=g(BestNode)+cost of getting from BestNode to Successor
A*算法详解——by Sunway - 白杨 - 白杨
    TileNumS = TileNum(x,y); // identification purposes
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨    
//子节点再Open表中吗?

A*算法详解——by Sunway - 白杨 - 白杨
    if ( (Old=CheckOPEN(TileNumS)) != NULL ) // if equal to NULL then not in OPEN list,
A*算法详解——by Sunway - 白杨 - 白杨                         
// else it returns the Node in Old

A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨
    A*算法详解——by Sunway - 白杨 - 白杨{
A*算法详解——by Sunway - 白杨 - 白杨      
//若在

A*算法详解——by Sunway - 白杨 - 白杨
      for( c = 0; c <8; c++)
A*算法详解——by Sunway - 白杨 - 白杨        
if( BestNode->Child[c] == NULL ) //
 Add Old to the list of BestNode's Children
A*算法详解——by Sunway - 白杨 - 白杨                         
// (or Successors).

A*算法详解——by Sunway - 白杨 - 白杨
         break;
A*算法详解——by Sunway - 白杨 - 白杨        BestNode
->Child[c] =
 Old;
A*算法详解——by Sunway - 白杨 - 白杨        
//比较Open表中的估价值和当前的估价值(只要比较g值就可以了)

A*算法详解——by Sunway - 白杨 - 白杨
        if ( g g ) // if our new g value is Parent = BestNode;
A*算法详解——by Sunway - 白杨 - 白杨
          Old->= g;
A*算法详解——by Sunway - 白杨 - 白杨          Old
->= g + Old->
h;
A*算法详解——by Sunway - 白杨 - 白杨        }

A*算法详解——by Sunway - 白杨 - 白杨      }

A*算法详解——by Sunway - 白杨 - 白杨      
else //在Closed表中吗?
A*算法详解——by Sunway - 白杨 - 白杨
        if ( (Old=CheckCLOSED(TileNumS)) != NULL ) //  if equal to NULL then not in OPEN list
A*算法详解——by Sunway - 白杨 - 白杨                              
// else it returns the Node in Old

A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨
        A*算法详解——by Sunway - 白杨 - 白杨 {
A*算法详解——by Sunway - 白杨 - 白杨          
//若在

A*算法详解——by Sunway - 白杨 - 白杨
          for( c = 0; c<8; c++)
A*算法详解——by Sunway - 白杨 - 白杨            
if ( BestNode->Child[c] == NULL ) //
 Add Old to the list of BestNode's
A*算法详解——by Sunway - 白杨 - 白杨                             
// Children (or Successors). break;

A*算法详解——by Sunway - 白杨 - 白杨
            BestNode->Child[c] = Old;
A*算法详解——by Sunway - 白杨 - 白杨            
//比较Closed表中的估价值和当前的估价值(只要比较g值就可以了)

A*算法详解——by Sunway - 白杨 - 白杨
            if ( g g ) // if our new g value is Parent = BestNode;
A*算法详解——by Sunway - 白杨 - 白杨
              Old->= g;
A*算法详解——by Sunway - 白杨 - 白杨              Old
->= g + Old->h; //再依次更新Old的所有子节点的估价值

A*算法详解——by Sunway - 白杨 - 白杨
              PropagateDown(Old); // Since we changed the g value of Old, we need
A*算法详解——by Sunway - 白杨 - 白杨                         
//
 to propagate this new value downwards, i.e.
A*算法详解——by Sunway - 白杨 - 白杨                         
// do a Depth-First traversal of the tree!

A*算法详解——by Sunway - 白杨 - 白杨
             }

A*算法详解——by Sunway - 白杨 - 白杨        }
A*算法详解——by Sunway - 白杨 - 白杨        
else //不在Open表中也不在Close表中
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨
        A*算法详解——by Sunway - 白杨 - 白杨 {
A*算法详解——by Sunway - 白杨 - 白杨          
//生成新的节点

A*算法详解——by Sunway - 白杨 - 白杨
          Successor = ( NODE* )calloc(1,sizeof( NODE ));
A*算法详解——by Sunway - 白杨 - 白杨          Successor
->Parent =
 BestNode;
A*算法详解——by Sunway - 白杨 - 白杨          Successor
->=
 g;
A*算法详解——by Sunway - 白杨 - 白杨          Successor
->= (x-dx)*(x-dx) + (y-dy)*(y-dy); // should do sqrt(), but since we

A*算法详解——by Sunway - 白杨 - 白杨
                                   don't really
A*算法详解——by Sunway - 白杨 - 白杨
          Successor->= g+Successor->h; // care about the distance but just which branch
A*算法详解——by Sunway - 白杨 - 白杨
          looks Successor->= x; // better this should suffice. Anyayz it's faster.
A*算法详解——by Sunway - 白杨 - 白杨
          Successor->= y;
A*算法详解——by Sunway - 白杨 - 白杨          Successor
->NodeNum =
 TileNumS;
A*算法详解——by Sunway - 白杨 - 白杨          
//再插入Open表中,同时排序。

A*算法详解——by Sunway - 白杨 - 白杨
          Insert(Successor); // Insert Successor on OPEN list wrt f
A*算法详解——by Sunway - 白杨 - 白杨
          for( c =0; c <8; c++)
A*算法详解——by Sunway - 白杨 - 白杨            
if ( BestNode->Child[c] == NULL ) // Add Old to the list of BestNode's

A*算法详解——by Sunway - 白杨 - 白杨
                              Children (or Successors).
A*算法详解——by Sunway - 白杨 - 白杨            
break
;
A*算法详解——by Sunway - 白杨 - 白杨          BestNode
->Child[c] =
 Successor;
A*算法详解——by Sunway - 白杨 - 白杨        }

A*算法详解——by Sunway - 白杨 - 白杨  }
A*算法详解——by Sunway - 白杨 - 白杨


  哈哈。A*算法我懂了。当然,我希望你有这样的感觉。不过我还要再说几句。仔细看看这个程序,你会发现,这个程序和我前面说的伪程序有一些不同,在GenerateSucc函数中,当子节点在Closed表中时,没有将子节点从Closed表中删除并放入Open表中。而是直接的重新的计算该节点的所有子节点的估价值(用PropagateDown函数)。这样可以快一些。另当子节点在Open表和Closed表中时,重新的计算估价值后,没有重新的对Open表中的节点排序,我有些想不通,为什么不排呢?会不会是一个小小的BUG。你知道告诉我好吗?
  好了。主要的内容都讲完了,还是完整仔细的看看源程序吧。希望我所的对你有一点帮助,一点点也可以。如果你对文章中的观点有异议或有更好的解释都告诉我。

----------------------------------------------------------------------------------------------------------------------------                                                                                                                                                ——by
Drew
                                                                                 对sunway程序中的BUG所进行的修改


需要注意的是Sunway上面文章“深入A*算法”中引用了一个A*的游戏程序进行讲解,并有这个源码的下载,不过它有一个不小的Bug, 就是新的子节点放入OPEN表中进行了排序,而当子节点在Open表和Closed表中时,重新计算估价值后,没有重新的对Open表中的节点排序,这个问题会导致计算有时得不到最优解,另外在路网权重悬殊很大时,搜索范围不但超过Dijkstra,甚至搜索全部路网, 使效率大大降低。 

Drew 对这个问题进行了如下修正,当子节点在Open表和Closed表中时,重新计算估价值后,删除OPEN表中的老的节点,将有新估价值的节点插入OPEN表中,重新排序,经测试效果良好,修改的代码如下,红色部分为Drew添加的代码.添加进程序的相应部分即可。

在函数GenerateSucc()中 
...................................

g=BestNode->g+1/**//* g(Successor)=g(BestNode)+cost of getting from BestNode to Successor */
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨TileNumS
=TileNum((int)x,(int)y); /**//* identification purposes */
A*算法详解——by Sunway - 白杨 - 白杨
if ((Old=CheckOPEN(TileNumS)) != NULL) 
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨

A*算法详解——by Sunway - 白杨 - 白杨
for(c=0;c<8;c++
)
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨
if(BestNode->Child[c] == NULL) /**//* Add Old to the list of BestNode's Children (or Successors). */

A*算法详解——by Sunway - 白杨 - 白杨
break;
A*算法详解——by Sunway - 白杨 - 白杨BestNode
->Child[c]=
Old;
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨
if (g < Old->
g) 
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨
{
A*算法详解——by Sunway - 白杨 - 白杨Old
->Parent=
BestNode;
A*算法详解——by Sunway - 白杨 - 白杨Old
->g=
g;
A*算法详解——by Sunway - 白杨 - 白杨Old
->f=g+Old->
h; 
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨 
A*算法详解——by Sunway - 白杨 - 白杨
//
Drew 在该处添加如下红色代码 
A*算法详解——by Sunway - 白杨 - 白杨
//Implement by Drew 

A*算法详解——by Sunway - 白杨 - 白杨
NODE *q,*p=OPEN->NextNode, *temp=OPEN->NextNode;
A*算法详解——by Sunway - 白杨 - 白杨
while(p!=NULL && p->NodeNum != Old->
NodeNum)
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨
{
A*算法详解——by Sunway - 白杨 - 白杨    q
=
p;
A*算法详解——by Sunway - 白杨 - 白杨    p
=p->
NextNode;
A*算法详解——by Sunway - 白杨 - 白杨}

A*算法详解——by Sunway - 白杨 - 白杨
if(p->NodeNum == Old->NodeNum)
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨
{
A*算法详解——by Sunway - 白杨 - 白杨   
if(p==OPEN->
NextNode)
A*算法详解——by Sunway - 白杨 - 白杨A*算法详解——by Sunway - 白杨 - 白杨  
A*算法详解——by Sunway - 白杨 - 白杨
{
A*算法详解——by Sunway - 白杨 - 白杨     temp 
= temp->
NextNode;
A*算法详解——by Sunway - 白杨 - 白杨     OPEN 
->NextNode =
 temp;
A*算法详解——by Sunway - 白杨 - 白杨  }

A*算法详解——by Sunway - 白杨 - 白杨  
else
A*算法详解——by Sunway - 白杨 - 白杨  q
->NextNode = p->NextNode;
A*算法详解——by Sunway - 白杨 - 白杨 }

A*算法详解——by Sunway - 白杨 - 白杨Insert(Old); 
// Insert Successor on OPEN list wrt f 
A*算法详解——by Sunway - 白杨 - 白杨
}
 
A*算法详解——by Sunway - 白杨 - 白杨
A*算法详解——by Sunway - 白杨 - 白杨


 

转自 http://hi.baidu.com/_sunboy_/item/4bef7c510cff32d8d58bac47http://xingyunbaijunwei.blog.163.com/blog/static/7653806720119775622411/

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
A*算法是一种常用于路径搜索的算法,可以用于解决许多实际问题,比如迷宫问题、机器人路径规划等等。在Matlab中实现A*算法可以按照以下步骤进行: 1. 输入参数:首先,你需要确定问题的起始状态、目标状态、以及其他可能的状态和动作。这些信息将用于定义问题的搜索空间。 2. 初始化变量:在开始搜索之前,你需要初始化一些变量,如开放列表和关闭列表。开放列表用于存储待扩展的节点,关闭列表用于存储已经扩展过的节点。 3. 循环过程:在每次循环中,你需要从开放列表中选择一个节点进行扩展。选择节点的方法一般是根据节点的启发式评估函数,选择具有最小评估值的节点。 4. 扩展节点:对于选定的节点,你需要考虑其邻居节点,并计算它们的启发式评估值。根据评估值的大小,你可以决定是否将邻居节点加入开放列表。 5. 循环后处理:在每次循环结束后,你需要更新一些变量,如节点的父节点和评估值。同时,你还需要检查是否已经找到了目标状态,如果找到了,可以结束搜索。 根据引用中给出的MATLAB代码,你可以按照上述步骤实现A*算法,并通过调试和验证来验证代码的正确性。你也可以参考引用中提到的博文,了解更多关于A*算法的详细介绍和手写步骤。 希望以上信息对你有帮助。如果需要更多细节,请参考引用中给出的MATLAB代码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [A星(A*、A Star)路径规划算法详解(附MATLAB代码)](https://blog.csdn.net/HuangChen666/article/details/125487491)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Matlab编程技巧:A*算法仿真](https://blog.csdn.net/u013288925/article/details/122628387)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值