A*算法(A-Star Algorithm)详解

A*算法(A-Star Algorithm)详解

A*算法(A-Star Algorithm)是一种启发式搜索算法,广泛应用于路径规划(如游戏寻路、机器人导航)、图遍历等领域。它通过结合实际代价启发式估计代价,在保证找到最优路径的同时,显著减少搜索范围,效率远高于传统的Dijkstra算法或贪心搜索。

在这里插入图片描述

一、核心思想:评估函数f(n)

A*算法的核心是定义一个评估函数,用于优先扩展“最有希望”到达目标的节点。该函数表示为:
f(n)=g(n)+h(n) f(n) = g(n) + h(n) f(n)=g(n)+h(n)

  • g(n):从起点(Start)到当前节点 nnn 的实际代价(已消耗的代价)。例如,在网格地图中,若每一步移动代价为1,则 g(n)g(n)g(n) 是起点到 nnn 的步数。
  • h(n):从当前节点 nnn 到目标节点(Goal)的估计代价(启发式预测)。它是算法的“智能”来源,需满足可采纳性(Admissible)——即不高估实际代价(否则可能错过最优解)。
  • f(n):节点 nnn 的总代价估计,指导搜索方向(优先扩展 f(n)f(n)f(n) 最小的节点)。
在这里插入图片描述

二、算法步骤

A*算法的执行流程可概括为以下步骤:

1. 初始化数据结构
  • 开放列表(Open List):优先队列(最小堆),存储待扩展的节点,按 f(n)f(n)f(n) 排序(fff 最小的节点在顶部)。初始时仅包含起点。
  • 关闭列表(Closed List):集合或哈希表,存储已扩展过的节点(避免重复处理)。初始为空。
  • 代价记录:维护两个字典(或数组),分别记录每个节点的 g(n)g(n)g(n)(实际代价)和 f(n)f(n)f(n)(总代价)。
2. 主循环:扩展节点

重复以下步骤直到找到目标或开放列表为空(无路径):

  • 步骤1:从开放列表中取出 f(n)f(n)f(n) 最小的节点 nnn(称为当前节点)。
  • 步骤2:若 nnn 是目标节点,回溯路径并返回结果(算法结束)。
  • 步骤3:将 nnn 加入关闭列表(标记为已处理)。
  • 步骤4:遍历 nnn 的所有邻居节点 mmm(上下左右、对角线等,取决于移动规则):
    • 若 mmm 在关闭列表中:跳过(已处理过更优路径)。
    • 计算临时 ggg 值:temp_g=g(n)+从n到m的移动代价temp\_g = g(n) + \text{从}n\text{到}m\text{的移动代价}temp_g=g(n)+从n到m的移动代价(如相邻节点代价为1,对角线为√2)。
    • 若 mmm 不在开放列表中,或 temp_g<g(m)temp\_g < g(m)temp_g<g(m)(发现更优路径):
      • 更新 g(m)=temp_gg(m) = temp\_gg(m)=temp_g。
      • 计算 h(m)h(m)h(m)(启发式估计值)。
      • 计算 f(m)=g(m)+h(m)f(m) = g(m) + h(m)f(m)=g(m)+h(m)。

若 mmm 不在开放列表中,将其加入开放列表;否则,更新其在开放列表中的优先级(因 f(m)f(m)f(m) 可能变小)。

在这里插入图片描述
3. 路径回溯

当目标节点被取出开放列表时,从目标节点反向回溯父节点(扩展时记录每个节点的父节点),直到回到起点,得到完整路径。

三、关键:启发函数h(n)的选择

h(n)h(n)h(n) 的选择直接影响算法效率和最优性。需满足可采纳性(不高估实际代价),常见类型如下:

1. 曼哈顿距离(Manhattan Distance)

适用于四方向移动(上下左右)的网格地图:
h(n)=∣xn−xgoal∣+∣yn−ygoal∣ h(n) = |x_n - x_{goal}| + |y_n - y_{goal}| h(n)=∣xn​−xgoal​∣+∣yn​−ygoal​∣
其中 (xn,yn)(x_n, y_n)(xn​,yn​) 是当前节点坐标,(xgoal,ygoal)(x_{goal}, y_{goal})(xgoal​,ygoal​) 是目标坐标。

2. 欧几里得距离(Euclidean Distance)

适用于八方向移动(允许对角线)的场景:
h(n)=(xn−xgoal)2+(yn−ygoal)2 h(n) = \sqrt{(x_n - x_{goal})^2 + (y_n - y_{goal})^2} h(n)=(xn​−xgoal​)2+(yn​−ygoal​)2​

3. 切比雪夫距离(Chebyshev Distance)

适用于八方向移动且允许斜向一步到位的情况(如国际象棋中的王):
h(n)=max⁡(∣xn−xgoal∣,∣yn−ygoal∣) h(n) = \max(|x_n - x_{goal}|, |y_n - y_{goal}|) h(n)=max(∣xn​−xgoal​∣,∣yn​−ygoal​∣)

4. 其他变种

根据具体问题设计专用启发函数(如路径规划中的预计算代价图)。

四、特性分析

  • 最优性:若 h(n)h(n)h(n) 可采纳(不高估),A* 一定能找到最短路径(前提是所有边的代价非负)。
  • 完备性:若存在路径且图有限,A* 最终会找到路径;若不存在路径,开放列表会为空。
  • 效率:启发函数 h(n)h(n)h(n) 越接近实际代价(但不超过),开放列表扩展的节点越少,效率越高。例如,当 h(n)h(n)h(n) 等于实际代价(仅目标节点的 h=0h=0h=0),A* 退化为Dijkstra算法(全局搜索);当 h(n)h(n)h(n) 强启发(如目标明确时的直线距离),搜索范围大幅缩小。
在这里插入图片描述

五、应用场景

  • 游戏开发:NPC角色寻路(如《魔兽世界》《英雄联盟》)。
  • 机器人导航:自动驾驶中的局部路径规划。
  • 地图服务:GPS导航中的实时路径计算(结合实时交通数据调整代价)。

六、示例:网格地图寻路

假设一个4x4网格(起点(0,0),终点(3,3)),四方向移动,每步代价为1。

  1. 初始化:开放列表包含起点(0,0),g=0g=0g=0,h=∣0−3∣+∣0−3∣=6h=|0-3|+|0-3|=6h=∣0−3∣+∣0−3∣=6,f=6f=6f=6。
  2. 第一次扩展:取出(0,0),扩展邻居(0,1)、(1,0)。计算它们的 g=1g=1g=1,hhh 分别为 ∣0−3∣+∣1−3∣=5|0-3|+|1-3|=5∣0−3∣+∣1−3∣=5(f=6f=6f=6)和 ∣1−3∣+∣0−3∣=5|1-3|+|0-3|=5∣1−3∣+∣0−3∣=5(f=6f=6f=6),加入开放列表。
  3. 后续扩展:每次选择 fff 最小的节点(初始阶段多个节点 f=6f=6f=6),逐步向终点逼近。最终当终点(3,3)被取出时,回溯路径为:(0,0)→(1,0)→(2,0)→(3,0)→(3,1)→(3,2)→(3,3)(或其他等价最短路径)。

总结

A*算法通过平衡实际代价与启发式估计,在路径规划中实现了“高效+最优”的双重优势。理解其核心评估函数、数据结构(开放/关闭列表)及启发函数的选择,是掌握该算法的关键。实际应用中,需根据场景调整启发函数,以在效率和最优性之间取得平衡。

在这里插入图片描述

用生活场景解释A*算法

要理解A算法,咱们可以用一个生活中找路的场景来打比方——就像你在陌生的小区里找朋友家,手里有一张地图(网格或道路图),需要最快找到目的地。A算法就是帮你“聪明选路”的小助手,它会一边算你已经走了多远(实际代价),一边猜剩下的路大概还要走多远(预估代价),最终带你走最快的那条路。

一、核心思路:用“总代价”决定先走哪条路

假设你现在在起点(比如小区门口),目标是朋友家(终点)。A*算法的关键是给每个“可能经过的点”(比如路上的每个路口、格子)算一个总代价分数,分数越低,说明这条路“越值得先走”。这个总分数由两部分组成:

  • g(n):你已经走了多远(实际代价)。比如从起点到当前点,你走了300米(或3步),g(n)=300。
  • h(n):你猜还要走多远(预估代价)。比如当前点离终点看起来还有200米(或2步),h(n)=200(但不能乱猜,得“靠谱”)。

总分数 f(n) = g(n) + h(n),相当于“从起点到终点经过这里的总步数/总距离”。A*算法会优先走f(n)最小的点——就像你会优先选“已经走了100米+还剩100米=总共200米”的路,而不是“已经走了200米+还剩300米=总共500米”的路。

二、具体怎么操作?像“整理待选清单”一样找路

A*算法的过程可以想象成你拿着一张“待选清单”(开放列表)和一张“已检查清单”(关闭列表),一步步缩小范围:

1. 开始:把起点放进待选清单

一开始,你只知道起点,所以待选清单里只有起点,它的g=0(还没走),h是你猜的起点到终点的距离(比如直线距离),f=g+h。

2. 循环:每次从待选清单里挑“最划算”的点

每次从待选清单里找出f(n)最小的点(也就是“最值得走”的点),把它从待选清单移到已检查清单(表示你已经认真考虑过这个点了)。

3. 检查是否到终点

如果这个点刚好是终点,恭喜!你已经找到路了,接下来只需要“倒推”回去,就能得到完整路径(比如:终点←上一步←再上一步←…←起点)。

4. 扩展邻居:看看周围有哪些路可选

如果还没到终点,你需要看看当前点的“邻居”(比如上下左右四个方向的路口,或者对角线的路口,取决于你能怎么走)。对每个邻居:

  • 如果邻居已经在已检查清单(你之前已经仔细看过这个点,而且当时的路线更优),跳过它(不用再浪费时间)。
  • 如果邻居不在待选清单,或者你找到了一条去邻居的“更短实际路径”(比如之前算过去邻居要走500米,现在发现走另一条路只要400米),就更新它的g(n)(实际走了多远),重新算f(n)=g(n)+h(n),然后把它放进待选清单。

三、关键:“猜得靠谱”才能找得快

A*算法好不好用,关键看你怎么“猜”h(n)(剩下的路有多远)。这个“猜测”必须满足一个条件:不能高估实际距离(比如实际要走200米,你不能猜300米)。否则,算法可能会漏掉真正的最短路径。

举个例子:

  • 如果你在走直角的网格路(比如只能上下左右走,不能斜着走),最靠谱的h(n)是“曼哈顿距离”——横竖两边的步数加起来。比如当前点在(2,3),终点在(5,7),那么横向需要走5-2=3步,纵向需要走7-3=4步,h(n)=3+4=7(实际可能需要更多步,但绝不会更少)。
  • 如果你可以斜着走(比如八方向移动),h(n)可以用“欧几里得距离”——直接算两点之间的直线距离(比如√[(5-2)²+(7-3)²]≈5),这比曼哈顿距离更接近实际步数。

四、为什么A*比“笨办法”好?

传统方法比如Dijkstra算法,相当于“盲目”地从起点开始,把所有可能的路都展开,直到找到终点(像撒网捕鱼)。而A*算法因为有h(n)的“聪明猜测”,会优先展开那些“看起来离终点更近”的点(像瞄准目标撒网),所以找路更快,计算量更小

总结:A*算法的本质

A*算法就像一个“聪明的导航员”:

  • 它知道你已经走了多远(g(n)),也知道大概还要走多远(h(n)),从而选出“总代价最小”的路。
  • 它不会乱猜(h(n)不吹牛),所以最终一定能找到最短路径(如果存在的话)。
  • 生活中,它能在游戏里帮角色快速找路、在导航软件里帮你避开拥堵(调整h(n)为实时路况),非常实用!

Read more

10秒上手中文语音识别,科哥构建的WebUI太友好了

10秒上手中文语音识别,科哥构建的WebUI太友好了 你有没有过这样的时刻:会议刚结束,录音文件堆在文件夹里发呆;采访素材躺在硬盘里吃灰;想把一段语音快速转成文字,却卡在环境配置、模型下载、代码调试的迷宫里?别折腾了——今天这个工具,真能让你10秒打开网页、30秒上传音频、1分钟拿到准确文字稿。 这不是概念演示,也不是简化版demo,而是基于阿里FunASR生态中性能顶尖的Speech Seaco Paraformer ASR模型,由开发者“科哥”亲手封装、反复打磨的WebUI镜像。它不依赖Python环境、不碰CUDA编译、不写一行代码,所有操作都在浏览器里完成。更关键的是:它专为中文场景优化,对“人工智能”“大模型”“端到端”这类高频术语识别稳得一批,还支持热词定制——这才是真正能进工作流的语音识别工具。 下面我就带你从零开始,不讲原理、不列参数、不堆术语,只说你点哪里、传什么、看什么、怎么用得更准。 1. 三步启动:不用装、不用配、

By Ne0inhk
【Java Web学习 | 第五篇】CSS(4) -盒子模型

【Java Web学习 | 第五篇】CSS(4) -盒子模型

🌈个人主页: Hygge_Code🔥热门专栏:从0开始学习Java | Linux学习| 计算机网络💫个人格言: “既然选择了远方,便不顾风雨兼程” 文章目录 * CSS盒子模型🥝 * 1. 什么是CSS盒子模型? * 2. 边框(border):盒子的"外衣"🍋‍🟩 * 边框的基本属性 * 单边边框设置 * 边框对盒子大小的影响 * 表格细线边框 * 3. 内边距(padding):内容与边框的缓冲带🍋‍🟩 * 内边距的基本用法 * 内边距对盒子大小的影响 * 内边距的实用技巧 * 内边距不影响盒子大小的特殊情况 * 4. 外边距(margin):盒子之间的距离🍋‍🟩 * 外边距的基本用法 * 外边距的典型应用:水平居中 * 外边距合并问题 * 清除默认内外边距🐦‍🔥 * 综合代码演示 * CSS美化三剑客:圆角边框、盒子阴影与文字阴影🥝 * 1. 圆角边框(border-radius):告别生

By Ne0inhk
总结前端三年 理想滚烫与现实的冰冷碰撞

总结前端三年 理想滚烫与现实的冰冷碰撞

大家好,我是500佰,技术宅男 目前正在前往独立开发路线,我会在这里分享关于编程技术、独立开发、技术资讯以及编程感悟等内容 6月3日的一篇《一个普通人的30岁 他经历了什么》介绍一篇自己的碎碎念、即回顾自己以前的成长经历,那么再接着说下这3年来的工作经历,2022年1月,我以一名前端新人的身份开始了职业生涯。每当看到浏览器中运行的网站、手机里流畅的APP,或是点击按钮后转动的loading图标,都会想到这些产品背后凝聚着无数开发者的心血。我既期待能成为这个创造数字世界的一员,又难免担心:自己的技术储备是否足够?会不会被身边优秀的同事远远甩在身后? 怀揣着对未来的憧憬与一丝忐忑,我正式踏入了职业生涯的第一站。 不断尝试和调整的前两年(2022 ~ 2024) 我的职业生涯始于一家颇具特色的企业。原本以为会从事移动应用或网站开发,没想到公司专注于打造一款独特产品——我们开发了一系列可复用组件,配合自主研发的拖拽式平台,能够快速搭建Web站点。这种模式与后来流行的低代码平台颇有相似之处。 作为一名Java工程师加入公司后,却发现实际工作内容与预期有较大差异。当时还不了解’前端开发’这个

By Ne0inhk