首页 > 编程语言 >【一看就会】路径规划算法【一】——广度优先,深度优先,Dijkstra、A*、D*

【一看就会】路径规划算法【一】——广度优先,深度优先,Dijkstra、A*、D*

时间:2025-01-14 15:57:47浏览次数:3  
标签:优先 权重 路径 Dijkstra 算法 搜索 广度 节点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

路径规划,就是在地图上,从起点到终点规划出一条最优路径。
【最优】,就像我们看高德地图一样,上面显示的:最短路径,最短时间,红灯最少,不走高速,避开监控等等。
这是【最优】的几种情况。
如果放在室内机器人,或者别的情况,【最优】还可能包含路径平滑性等等。

那如何得到这些路径呢。
那最最简单的,从一个节点开始,把所有所有的路径都写出来,然后计算每个路径的长度,红绿灯数,是否有高速,曲率等等,然后再选出来。
但是很明显,这数据量会大到可怕,消耗的时间和资源都很难承受起。

于是就开始了路径规划算法的研究,也就是说所有的路径规划算法都是为了能够解决暴力搜索的效率低下和占用资源高的问题,同时适应动态坏境。

路径规划的算法有很多,这片文章主要讲其中六种,主要为了让大家更好的进行理解,不涉及到具体的程序实现。
这六种算法分别是:
1.广度优先搜索
2.深度优先搜索
3.Dijkstra
4.A*
5.D*
6.RRT


一、输入输出

在讲解具体算法前,先明确一下输入和输出。

1.输入

输入:环境、约束条件和目标。

环境

地图通常用三种方式表示:
1.图结构:
节点(顶点):表示关键位置(如城市、路口、房间等)。
边:表示节点之间的连接路径,可能带有权重(如距离、时间或费用)。
示例:邻接矩阵、邻接表、边列表等。
比如:

邻接矩阵:
[
    [0, 2, ∞],
    [2, 0, 3],
    [∞, 3, 0]
]

2.栅格地图
将环境划分为网格,每个网格包含通行性信息(如可通行/障碍物)。

0 0 1
0 1 0
0 0 0  (0表示可通行,1表示障碍)

3.连续空间表示
使用多边形、线段或函数描述环境边界和障碍物。

约束条件

最大路径长度,最长时间。

目标

起点和终点。
目标函数的优化目标,如最短路径、最少时间、最大安全性等。

其他

动态更新的环境变化,比如哪修路,哪突然不能走了等。

2.输出

输出主要有两部分:路径,路径代价
路径就是一堆离散的点。
路径代价就是每段路径的总距离,总时间,总红绿灯数等等。

二、广度优先搜索——BFS

广度优先搜索和深度优先搜索都是最基础的路径规划算法。
网上有很多动画,可以帮助大家快速理解。
在此简单说明一下,广度优先搜索就是一种层式遍历,从起点开始,一次访问下一层的节点,以此遍历下去,直至找到目标节点。

三、深度优先搜索——DFS

深度优先搜索就是先一条路走到底,然后再返回上一个节点,看还有没有别的路,再走到底,要是没路了,就再返回上一个节点,走别的路走到底。

在这里插入图片描述

先讲这两种最基础最简单的搜索,是为了给下面的几种算法做铺垫,可以说,

四、Dijkstra

Dijkstra也很好理解,它是一种层式贪心算法。
所适用的是权重图。
在实际的道路中,每两个点之间的道路都有距离,这个距离就可以作为权重,当然像是堵车程度,红绿灯数量,都可以作为权重。这就是权重图。
贪心算法大家经常听到,指的是把一个大问题拆成若干小问题,每次只考虑每个小问题最优。
放到路径规划中,就是从节点出发,遍历下一层的节点时,选择权重最小的节点。
借用抖音上的一张图:
在这里插入图片描述
从节点0开始,一层一层的遍历,并更新最近点路径,并记录已经到达的节点,比如说,到节点7,有直接到7和先到1再到7两种,一个权重8,一个权重15,那就将8的那条作为到点7的最优路径进行记录,以此类推,优先搜索权重小的那一条路径。
只要图的联通的,Dijkstra会将所有的节点都遍历一遍,找出到所有节点的最短路径。

五、A*

以上的三种算法,都有个共性:都是盲人在走迷宫。
也就是说,以上三种算法,都是不知道终点与起点的位置关系在走,所以只能一层一层,或者一根一根的依次把所有能走的路走一遍,然后撞到“终点”才停止。
很明显这种方式都很傻,因为我们明明是知道终点距离起点的位置和方向的。
所以,就有了A算法。
A
算法,使用了启发式函数f(n),来进行优化。
启发式函数包含两部分:
g(n):从起点到当前节点的成本,也就是Dijkstra中的权重。
h(n):从当前节点到终点的启发式估计成本。

细讲一下h(n)是怎么回事。
以距离最短为目标,起点到终点的距离表示,除了欧拉距离之外,还可以用曼哈顿距离表示,也就是两条直角边的和,入图:
在这里插入图片描述
h(n)就是当前节点距离终点的曼哈顿距离。

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

每一步层式遍历后,都选取f(n)最小的节点,进行下一步遍历,直到h(n)=0.也就相当于走到了终点。

可以发现,A*算法可以说是在Dijkstra算法上进一步变种。

六、D*

上面的所有算法都有一个问题:就是无法适应动态环境,如果地图有变化,那就需要重新算一遍。
于是,就有了D算法。
D
(Dynamic A*)算法又是A算法的改进版本。
D
算法的核心目标是在动态环境中找到从起点到目标的最优路径,同时在环境发生变化时,通过局部更新而非全图重新计算路径,而不再需要重新从头到尾算一遍。

继续带着问题找答案。
为了实现路径的动态调整,D* 算法采用了一种“反向搜索+增量更新”的方式。

首先是【反向搜索】,顾名思义,与上面的算法都不同,D* 是从终点到起点的搜索。
【增量更新】,就是当当环境中某条边的权重发生变化(如障碍物阻挡路径),仅更新受影响节点的 rhs(n) 和 g(n),并将这些节点重新加入开放集合。

哎?这里的rhs(n) 和 g(n)指的是什么呢?
上面说过D是A的改进版本,所以A的思想依然延续。
依然是计算总代价函数f(x)。
f(x)=min(g(n),rhs(n))+h(n)
其中:
g(n):从起点到节点n 的当前已知最小代价。
rhs(n):从当前节点通过某条边到达邻居节点的估计代价。
h(n):启发式估计代价,用于引导搜索。
双代价系统(g(n) 和 rhs(n)):g(n):实际路径代价,表示从起点到当前节点的最佳已知代价。
rhs(n):备选代价,表示从当前节点通过某条边到目标节点的代价。
在每次节点扩展时,D
会调整 g(n) 和 rhs(n) 的值,以维护路径最优性。

理解不了没关系,毕竟是干巴巴的概念,下面让我们举个栗子。

假设路径图如下:

      A
      / \
    1   5
   /        \
  B---2---C
  |   \        |
  4    6    3
  |        \   |
  D---3----E
   \           /
   2         1
    \         /
         F

数字表示每个节点之间的路径之间的权重。
目标:从 A 到 F 找最优路径。
解题过程如下:

1.初始路径规划(环境未变化)

1.所有节点初始化为g(x)=∞。
2.从目标节点 F 开始,设置g(F)=0。
3.反向计算邻居节点的g 值:
g(D)=g(F)+2=2
g(E)=g(F)+1=1
4.继续更新其余节点:
在这里插入图片描述
于是得到了从F-A的最优路径。

2.环境变化

假设环境发生变化,路径 B -> D 被障碍阻塞,权重从 4 变为 ∞,需要动态调整路径。

3.动态调整

1.受影响节点标记

B -> D 的权重变化影响节点 B 和 D。
B和D 被标记为受影响节点,加入开放集合(Open List)。

2.局部更新.

1.重新计算 g(D):
新的 g(D)=min(g(F)+2,g(E)+3)=min(2,4)=2。
由于g(D) 未变化,停止对 D 的进一步更新。
2.重新计算 g(B):
新的路径:g(B)=min(g(D)+4,g(E)+6)=min(∞,7)=7。
更新后,g(B) 的值变为 7。
3.重新计算 g(A):
更新后,g(A)=min(g(B)+1,g©+5)=min(8,9)=8。

D*算法在局部更新路径的原理,就是当某段路径权重发生变化时,将影响的节点从起点到终点,重新进行路径规划,然后一个开放集合,一个封闭集合,分别放这些东西。
路径规划这部分的逻辑不难,感觉实现起来怎么存储路径,这几个集合翻腾起来反而是难度比较大的地方。

总结

以上算法是一些基础路径规划算法,核心逻辑都是BFS和DFS,除了这类算法之外,还有像RRT等规划算法,在之后的规划算法介绍中会逐一和大家解释。

标签:优先,权重,路径,Dijkstra,算法,搜索,广度,节点
From: https://blog.csdn.net/weixin_48386130/article/details/144772782

相关文章

  • RabbitMQ-优先级队列及消息配置
    优先级队列C#数据类型queue----先进先出RabbitMQ---队列-----默认也是先进先出~~RabbitMQ设置优先级----可以配置让消费顺序,不按照先进先出的默认规则;给定的优先级---最终体现在消费者;优先级越高,消费的时候,就优先消费。就在前面消费案例:设置{"vip1","hello2","wor......
  • Java算法 数据结构 栈 队列 优先队列 比较器
    目录栈Stack性质构造方法代码示例队列Queue性质构造方法代码示例优先队列PriorityQueue性质构造方法代码示例比较器1.Comparator接口的方法2.常见的内置比较器1.自然排序比较器(naturalOrder())2.逆序排序比较器(reverseOrder())3.nullsFirst()......
  • 【IO编程】深度优先遍历
    **深度优先遍历目录(Depth-FirstTraversal)**是一种递归或栈式的目录遍历方法,优先深入到子目录中,再回溯到父目录继续遍历其他子目录。这是一种常见的文件系统操作,适用于查找文件、统计目录大小等场景。深度优先遍历完整思路递归式遍历:优先进入子目录,完成当前目录所有子目录......
  • 说说你对HTML元素的显示优先级的理解
    在前端开发中,HTML元素的显示优先级通常是由多个因素共同决定的,包括HTML的源代码顺序、CSS样式规则、以及JavaScript的动态修改。这里我们主要讨论的是在没有JavaScript干预,且CSS规则不冲突的情况下的显示优先级。HTML源代码顺序:在默认情况下,HTML元素按照它们在源代码中出现的顺......
  • 说说CSS的优先级是如何计算的?
    CSS的优先级计算是一个相对复杂但又非常重要的概念,在前端开发中,它决定了当多个样式规则应用于同一个元素时,哪个规则将最终生效。以下是CSS优先级计算的详细解释:1.优先级计算的基础CSS的优先级主要由选择器的类型和它们出现的次数决定。每个选择器都有一个相应的权重值,这些权重......
  • 探讨人工智能机器人学之路径规划与导航:A*算法、Dijkstra算法等路径规划方法
    引言在人工智能(AI)和机器人学中,路径规划与导航是一个至关重要的课题。机器人在复杂的环境中,必须能够根据环境信息和目标要求,自动计算一条从起始位置到目标位置的最优或可行的路径。路径规划不仅仅是关于如何找到目标位置,还涉及如何在多变、动态的环境中避免障碍、实现效率和安......
  • 蜘蛛织网--广度优先搜索和深度优先搜索在学习策略上的一些考量(1)
    如果把学习的过程想象为一个建立一张蛛网的过程,那么广度优先就是优先蛛网的大小,深度优先就是优先蛛丝的强度。那么现在的问题是什么?时间是有限的,进步也是有限的,想让网抓到想要的虫子(解决问题更加合理),我们就必须仔细考量网的大小和强度--即蛛网的大小和强度由所需要捕捉到的虫子(需......
  • dijkstra算法
      Dijkstra算法是用于计算图中单源最短路径的经典算法,其核心思想是贪心算法,通过不断选择当前距离源点最近的节点,更新源点到其他节点的距离,直到所有节点都被访问过。算法步骤初始化:设源点为s,定义一个数组dist[]来存储从源点s到各个顶点的最短距离,初始时,源点s到自身的......
  • E - Takahashi is Slime 2 (优先队列)
    题目链接:https://atcoder.jp/contests/abc384/tasks/abc384_e题意:粘液能够吸收比他严格小x倍的格子,并获得这个格子的力量(同时格子被粘液填充),让你求粘液能达到的最大力量值。思路:优先队列priortiy_queue.每次挑粘液上下左右四个格子入列,由于优先队列维护得到四个格子中最小的......
  • 如何设计一个能根据任务优先级来执行的线程池
    不同的线程池会选用不同的阻塞队列作为任务队列,比如FixedThreadPool使用的是LinkedBlockingQueue(有界队列),默认构造器初始的队列长度为Integer.MAX_VALUE,由于队列永远不会被放满,因此FixedThreadPool最多只能创建核心线程数的线程。假如需要实现一个优先级任务线程池的话,那可......