A*算法理解

广度优先(BFS)和深度优先(DFS)搜索

在谈A*之前,还是要先聊聊搜索算法中的老祖宗,深度和广度优先搜索算法。这两个算法,基本上各教科书都会有讲解,各种面试基本上也都会面到。不过为了讲清楚A*,我们还是先一起来看看他们吧。

 

深度优先搜索,用俗话说就是不见棺材不回头。算法会朝一个方向进发,直到遇到边界或者障碍物,才回溯。一般在实现的时候,我们采用递归的方式来进行,也可以采用模拟压栈的方式来实现。

 

如下图,S代表起点,E代表终点。我们如果按照右、下、左、上这样的扩展顺序的话,算法就会一直往右扩张,直到走到地图的右边界,发现没找到目标点,然后再回溯。

 

 

 

这个算法的好处就是实现简单,可能就十几行代码。不过问题也很明显,就是:

1、路径可能不是最优解;

2、寻路时间比较长。

 

广度优先搜索,这个用形象的比喻,就像是地震波,从起点向外辐射,直到找到目标点。我们在实现的时候,一般采用队列来实现。

 

 

 

这个算法的优点:

1、简单。代码也就几十行;

2、路径能找到最优解;

 

不足:

1、算法消耗的时间比较大,遍历的点会很多。

 

这里就引出一个问题:为什么广度优先算法能找到最优路径,但是却很耗时呢?

 

A*算法

广度优先搜索之所以能找到最优的路径,原因就是每一次扩展的点,都是距离出发点最近、步骤最少的。如此这样递推,当扩展到目标点的时候,也是距离出发点最近的。这样的路径自然形成了最短的路线。

 

任何事情都有正反两面。正是由于广度优先搜索一层层的扩展,虽然让他找到了最优的路线,但是,他却很傻的走完了绝大多数格子,才找到我们的目标点。也就是,他只关注了当前扩展点和出发点的关系,而忽略了当前点和目标点的距离。如果,如果,如果……我们每扩展一个点,就踮起脚尖,看看诗和远方,找找我们要寻找的那个目标,是不是就有可能指引我们快速的去往正确的方向,而不用傻乎乎的一层层的发展了呢?

 

我们来看看下图:

 

 

 

同样是从出发点S走了两步以后到达的M1和M2两个点,如果让你来选择,你会选择他们中的谁来做扩展点呢?很明显,只要是眼力不差的人,都会选择M1。为什么呢?因为M2需要再走9步,才能到达终点E;而M1只需要7步!!!

 

注意了!我们的判断依据,除了考虑了中间这个点同出发点的距离以外,还考虑了这个点同目标点的距离,对吧~

 

如果你想到了这一点,恭喜你,你已经掌握了A*算法的秘诀了:A*算法相对广度优先搜索算法,除了考虑中间某个点同出发点的距离以外,还考虑了这个点同目标点的距离。这就是A*算法比广度优先算法智能的地方。也就是所谓的启发式搜索。

 

我们简单的抽象一下,如果用f(M)表示:从起点S到终点E(经过M点)的距离,那他就可以表示成为两段距离之和,即:S→M的距离 + M→E的距离。如果我们用符号表示的话,就可以写成:f(M) = g(M) + h(M)。

 

 

 

怎么样,看起来这个公式是否是很简单呢?

 

我们扩展到M点的时候,S→M的距离就已经知道,所以g(M)是已知的。但是M到E的距离我们还不知道。如果我们能用某种公式,能大概预测一下这个距离,而这个预测的值又比较精确,我们是不是就能很精确的知道每一个即将扩展的点是否是最优的解路径上的点呢?这样找起路来,是不是就很快呢?

 

所以,接下来最关键的问题,就是怎么计算这个h(M)的值!

 

可能大家都会问一个问题:从M→E的距离不是很好计算嘛?用横向的距离+纵向的距离就完了!

 

这个问题问的很好,但是结论是:既对,又不对。如果按照我们之前的图来看,这个结论是正确的。但是,如果是下面这张图呢?

 

 

 

在M和E之间,有一堵蓝色的墙,这个时候,M→E的距离,还是横向的直线距离 + 纵向的直线距离嘛?明显不是了,他需要绕道!

 

这个时候,似乎希望破灭了……

 

前两天有个朋友给我说,两口子的相处之道,就是相互包容,不要太较真儿。如果我们将这个思想用到这里,把h(M)看做一个估计的值,而不是精确值,那问题是不是就解决了呢?

 

也就是说,我们尽可能找那些f(M)=g(M)+h(M)小的点(其中h(M)是个估算值),当做我们的路径经过点,即使实际的h'(M)值可能和h(M)值不等也没关系,我们就当做一个参考(总比广度优先搜索好吧~)。如果通过这个估算,能干掉很多明显很差的点,我们也就节省了很多不必要的花销,也算赚到了,对吧~

 

 

 

比如,上图中, M点即使是绕路,也比M'点要强,对吧。在估算的时候,我们就可以将S左边的点基本上都抛弃掉,从而减少我们扩展的点数,节约计算的时间。

 

说完上面的东东,我们大面儿上的东西就说的差不多了,接下来就省两个问题要去解决了:

1、这个估算的函数h(M)怎么样去计算?

2、对于不同的估算函数h(M)来讲,对于我们的搜索结果会有什么样的影响?

 

那我么一个个的来回答吧。

 

估算函数h(M)如何计算?

常见的距离计算公式有这么几种:

 

1、曼哈顿距离:这个名字听起来好高端,说白了,就是上面我们讲的横向格子数+纵向格子数;

2、欧式距离:这个名字听起来也很高端,说白了,就是两点间的直线距离sqrt((x1-x2)2 + (y1-y2)2)

 

除了上述的距离计算公式以外,还有一些变种的距离计算公式,如:对角线距离等等。这个就在具体的问题中做具体的优化了。

 

不同估算函数对于结果的影响

那距离公式选择不同,对我们的寻路结果有哪些影响呢?

 

1、当估算的距离h完全等于实际距离h'时,也就是每次扩展的那个点我们都准确的知道,如果选他以后,我们的路径距离是多少,这样我们就不用乱选了,每次都选最小的那个,一路下去,肯定就是最优的解,而且基本不用扩展其他的点。如下图:

 

 

 

2、如果估算距离h小于实际距离h'时,我们到最后一定能找到一条最短路径(如果存在另外一条更短的评估路径,就会选择更小的那个),但是有可能会经过很多无效的点。极端情况,当h==0的时候,最终的距离函数就变成:

 

f(M)=g(M)+h(M)

=> f(M)=g(M)+0

=> f(M)=g(M)

 

这不就是我们的广度优先搜索算法嘛?! 他只考虑和起始点的距离关系,毫无启发而言。

 

 

 

3、如果估算距离h大于实际距离h'时,有可能就很快找到一条通往目的地的路径,但是却不一定是最优的解。

 

因此,A*算法最后留给我们的,就是在时间和距离上需要考虑的一个平衡。如果要求最短距离,则一定选择h小于等于实际距离;如果不一定求解最优解,而是要速度快,则可以选择h大于等于实际距离。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: A*算法是一种常用于路径搜索和图形化问题的算法,它可以在给定的图形中找到从起点到终点的最短路径。该算法在Matlab中也可以很方便地实现。 在Matlab中实现A*算法的一种方法是使用优先级队列和响应函数。我们可以定义一个结构体来表示每个节点,并包含节点的坐标、G值、H值和父节点等信息。 首先,需要创建一个二维数组来表示地图。将起始点和目标点的坐标保存在变量中。 然后,创建一个优先级队列,并将起始节点添加到队列中。 接下来,使用循环不断从队列中取出优先级最高的节点,直到队列为空或者找到目标节点。 对于当前节点,首先计算当前节点到起始节点的G值,然后计算当前节点到目标节点的H值。将G值和H值相加得到F值。 然后,对当前节点的邻居节点进行遍历,如果邻居节点是障碍物或已经在关闭列表中,则忽略。如果邻居节点不在开放列表中,则将其添加到队列,并设置其父节点为当前节点。同时,更新邻居节点的G值、H值和F值。 如果找到目标节点,则跟踪其父节点并构建最短路径。 最后,将路径可视化在地图上,并返回最短路径。 在使用Matlab实现A*算法时,需要注意算法的效率和地图的大小。对于较大的地图,可能需要采取一些优化措施,例如使用网格分割。此外,还可以调整启发函数的权重,以便在不同场景下得到更合适的路径。 总之,A*算法是一个在Matlab中实现路径搜索的非常有用的算法,它可以为我们提供从起点到终点的最短路径。 ### 回答2: A*算法是一种用于在图中寻找最短路径的搜索算法。它在计算机科学和人工智能领域得到了广泛应用。而MATLAB是一种用于进行科学计算和数据可视化的高级编程语言和环境。下面我将结合这两个概念来回答你的问题。 A*算法在寻找图中最短路径时,综合考虑了路径的实际距离和启发式估计的距离。它使用一个开放列表和一个关闭列表来实现搜索过程。首先,将起始节点加入开放列表,然后迭代地选择开放列表中的节点,并计算从起始节点到当前节点的实际距离和启发式估计距离的和。然后根据该和来计算当前节点的总估计距离。接下来,将当前节点加入关闭列表,并将其相邻的未访问节点加入开放列表。不断重复上述步骤,直到找到目标节点或开放列表为空。 对于MATLAB来说,它提供了一些函数和工具箱,可以帮助我们在实现A*算法时进行图的表示和操作。例如,我们可以使用MATLAB的图和图算法工具箱来创建和操作图,使用图的节点和边的属性来表示实际距离,并使用内置函数来计算节点间的启发式估计距离。 此外,MATLAB还提供了可视化工具,可以帮助我们将图和路径可视化出来,以便更好地理解和分析算法的结果。我们可以使用MATLAB的绘图函数来绘制节点和边,使用标记或颜色来表示不同节点的状态,同时在图上绘制出A*算法找到的最短路径。 总的来说,通过结合A*算法和MATLAB,我们可以在图中快速有效地找到最短路径,并使用MATLAB的功能来可视化和分析结果。这两个概念相辅相成,为我们解决问题提供了强大的工具和方法。 ### 回答3: A*算法是一种常用于路径规划问题的启发式搜索算法,其目标是在地图或图形中找到两个节点之间的最短路径。A*算法综合了Dijkstra算法的广度优先搜索和贪婪搜索算法优势,能够快速、高效地找到最优解。 在Matlab中,我们可以通过以下步骤实现A*算法: 1. 创建地图:首先,我们需要创建一个表示地图的二维数组或矩阵。其中,可行的路径可以用0表示,障碍物或不可行的路径可以用1表示。 2. 定义节点和距离:我们需要定义起始节点和目标节点,并计算它们之间的距离。通常,我们使用欧几里得距离或曼哈顿距离进行距离计算。 3. 估计函数:A*算法中的关键是估计函数f(n)。这个函数可以表示为f(n) = g(n) + h(n),其中g(n)表示从起始节点到当前节点n的实际代价,h(n)表示从当前节点n到目标节点的启发式估计代价。 4. 创建开放和关闭列表:开放列表用于存储待探索的节点,关闭列表用于存储已经探索过的节点。 5. 初始化:将起始节点添加到开放列表中,设置其g(n)为0,计算h(n)并设置f(n)为h(n)。 6. 迭代搜索:进入一个循环,直到找到目标节点或者开放列表为空。在每次循环中,选择开放列表中f(n)值最小的节点进行探索。 7. 遍历相邻节点:对于选择的节点,遍历其相邻节点。对于每个相邻节点,计算g(n)和h(n),并计算f(n)。 8. 更新开放列表和关闭列表:将相邻节点添加到开放列表中,并将其父节点设置为当前节点。同时,将当前节点添加到关闭列表中。 9. 回溯路径:如果找到目标节点,从目标节点开始回溯父节点,直到回溯到起始节点。这样就可以得到最短路径。 通过上述步骤,我们可以在Matlab中实现A*算法,快速找到起始节点到目标节点的最短路径。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值