72人参与 • 2024-08-06 • 算法
前言:本文只是简单的介绍一下各路径规划算法的概念和流程,可用于对算法的初步了解,如果要进一步学习,可以在个人理解中找到我推荐的其他博主更为完善的文章。
目录
dijkstra算法是一种用于求解图中单源最短路径问题的经典算法。它可以用来找到从一个顶点到其他所有顶点的最短路径。
以下是dijkstra算法的基本概念:
dijkstra算法的基本思想是通过不断更新距离集合中的距离,逐步找到最短路径。它保证每次迭代都会选择当前距离最短的顶点作为下一个当前顶点,并通过该顶点更新其他顶点的距离。最终,得到起点到其他所有顶点的最短路径和对应的距离。
dijkstra算法的基本流程如下:
通过以上流程,dijkstra算法能够逐步更新距离集合中的距离,最终得到从起点到其他所有顶点的最短路径和对应的距离。
说白了就是问你:上面的图你怎么走可以把所有的点都走一遍,然后还需要路径长度最短。
这方法给出的答案是:我一个个点去摸索,比如我先从0到2最近,然后再从2开始摸索,发现接下来走1最好,因为0-2-1是5米,但0-2-3是8,0-2-5是10,然后我们确定0-2-1之后,再从1开始摸索,就这样慢慢找,最后找到最短路径。
具体学习可以参考这篇文章:图算法——求最短路径(dijkstra算法)
%在这个代码中,首先定义了一个带权有向图的邻接矩阵,然后定义了起点和终点。接着,初始化到各个节点的距离、前驱节点和已访问状态。然后,运行dijkstra算法,找到最短路径和最短距离。最后,使用matlab的fprintf函数输出结果。
% 定义带权有向图
n = 5; % 节点数
adj_matrix = [0 10 0 5 0; 0 0 1 2 0; 0 0 0 0 4; 0 3 9 0 2; 7 0 6 0 0]; % 邻接矩阵
% 初始化
start_node = 1; % 起点
end_node = 5; % 终点
dist = inf(1, n); % 到各个节点的距离
prev = zeros(1, n); % 前驱节点
visited = zeros(1, n); % 是否已访问
dist(start_node) = 0;
% 运行dijkstra算法
for i = 1:n
% 找到最近的未访问节点
min_dist = inf;
for j = 1:n
if visited(j) == 0 && dist(j) < min_dist
min_dist = dist(j);
curr_node = j;
end
end
% 更新距离和前驱节点
visited(curr_node) = 1;
for j = 1:n
if adj_matrix(curr_node, j) > 0 && visited(j) == 0
new_dist = dist(curr_node) + adj_matrix(curr_node, j);
if new_dist < dist(j)
dist(j) = new_dist;
prev(j) = curr_node;
end
end
end
end
% 输出结果
path = [end_node];
while path(1) ~= start_node
path = [prev(path(1)), path];
end
fprintf('最短路径:');
fprintf('%d ', path);
fprintf('\n最短距离:%d\n', dist(end_node));
floyd算法又称为floyd-warshall算法,是一种动态规划算法,用于解决任意两点之间的最短路径问题。该算法在图中存在负权边和环的情况下仍然保证正确性。
floyd算法的思想是动态规划,通过枚举所有可能的中间节点,来逐步更新每个节点之间的距离。具体而言,算法根据当前结点之间的最短路径和中间节点更新后的最短路径,依次更新每个节点之间的最短路径。由于每次先将中间节点作为当前节点进行考虑,再按照不同的中间节点进行循环,所以也被称为多源最短路径算法。
值得注意的是,在floyd算法中,对于每个中间节点k,都会更新一次所有顶点之间的距离,时间复杂度为o(n^3)。因此,floyd算法适用于顶点数较少的图,对于大型图来说效率较低。
还是这个图,只不过这个算法更容易找的是任意两点之间的最短距离,我们需要先弄个2维数组,然后一个点一个点的去修改权重,最后得出结果,不过这个算法可以解决负权边的情况,这也是他的优点。(但是是真的蛮麻烦的,如果顶点多要累死)
这是其他博主得出的结果,具体学习可以看他的这篇文章:图算法——求最短路径(floyd算法)
%在这个代码中,首先定义了一个带权有向图的邻接矩阵。然后,初始化到各个节点的距离。接着,运行floyd算法,计算出最短路径。最后,使用matlab的fprintf函数输出结果。
% 定义带权有向图
n = 5; % 节点数
adj_matrix = [0 10 inf 5 inf; inf 0 1 2 inf; inf inf 0 inf 4; inf 3 9 0 2; 7 inf 6 inf 0]; % 邻接矩阵
% 初始化
dist = adj_matrix;
for i = 1:n
dist(i, i) = 0;
end
% 运行floyd算法
for k = 1:n
for i = 1:n
for j = 1:n
if dist(i, k) + dist(k, j) < dist(i, j)
dist(i, j) = dist(i, k) + dist(k, j);
end
end
end
end
% 输出结果
fprintf('最短路径:\n');
for i = 1:n
for j = 1:n
if dist(i, j) == inf
fprintf('inf\t');
else
fprintf('%d\t', dist(i, j));
end
end
fprintf('\n');
end
(说白了就是dijkstra算法plus版,只不过他是先找到最优点,省了时间)
a*算法是一种启发式搜索算法,用于在图形或网络中找到最短路径。它结合了dijkstra算法的广度优先搜索和启发式函数的评估,以提高搜索效率。
a*算法通过下面这个函数来计算每个节点的优先级。
f ( n ) = g ( n ) + h ( n )
其中:
a*算法在解决图形搜索、迷宫问题、游戏ai等领域具有广泛应用。它在搜索过程中利用了启发式函数的启发性信息,能够快速找到最短路径,并且在启发式函数设计得当的情况下,可以保证找到最优解。
(执行算法的过程中,每个点需要记录达到该点的前一个点的位置 – 可以称之为父节点。这样做之后,一旦到达终点,便可以从终点开始,反过来顺着父节点的顺序找到起点,由此就构成了一条路径。)
这个算法难就难在根据情况去设估价函数了,需要一个函数给每个点以及点之间的距离算出代价,然后根据算出的结果加快整个寻找最短路径的过程,有了整个估算,就照着算法的流程,从代价小的来就行。
具体学习可以参考这篇文章:a*算法(超级详细讲解)
这个代码需要自己定义一部分函数。
%需要根据具体问题和数据结构进行适当的修改和调整。代码使用了优先队列数据结构(priorityqueue),需要定义启发式函数(heuristicfunc)和节点邻接函数(adjacencyfunc),以适应具体问题。
function [path, cost] = astar(startnode, goalnode, heuristicfunc, adjacencyfunc)
% 初始化open和closed列表
openlist = priorityqueue();
closedlist = containers.map();
% 将起始节点添加到open列表
openlist.insert(startnode, 0);
% 初始化节点的代价和父节点
gcost = containers.map();
gcost(startnode) = 0;
parent = containers.map();
% 开始a*搜索
while ~openlist.isempty()
% 从open列表中选择代价最小的节点
currentnode = openlist.extractmin();
% 如果当前节点是目标节点,则构建路径并返回
if currentnode == goalnode
path = constructpath(parent, currentnode);
cost = gcost(goalnode);
return;
end
% 将当前节点添加到closed列表
closedlist(currentnode) = true;
% 获取当前节点的邻居节点
neighbors = adjacencyfunc(currentnode);
for i = 1:length(neighbors)
neighbor = neighbors(i);
% 如果邻居节点在closed列表中,跳过
if iskey(closedlist, neighbor)
continue;
end
% 计算从起始节点到邻居节点的代价
tentativegcost = gcost(currentnode) + distance(currentnode, neighbor);
% 如果邻居节点不在open列表中,或者新的代价更小
if ~openlist.contains(neighbor) || tentativegcost < gcost(neighbor)
% 更新邻居节点的代价和父节点
gcost(neighbor) = tentativegcost;
parent(neighbor) = currentnode;
% 计算a*的估计总代价(f值)
fvalue = gcost(neighbor) + heuristicfunc(neighbor, goalnode);
% 将邻居节点添加到open列表或更新其代价
if ~openlist.contains(neighbor)
openlist.insert(neighbor, fvalue);
else
openlist.decreasekey(neighbor, fvalue);
end
end
end
end
% 如果open列表为空,说明无法找到路径
path = [];
cost = -1;
end
function path = constructpath(parent, node)
% 根据父节点构建路径
path = [];
while iskey(parent, node)
path = [node path];
node = parent(node);
end
path = [node path];
end
d*(d-star)算法是一种增量式路径规划算法,用于在动态环境中更新和重新规划路径。它是 a* 算法的扩展,可以有效地应对环境状态的变化。
算法是一种基于启发式搜索的路径规划算法,它可以在动态环境中找到最短路径。与a算法不同,d算法是增量式的,也就是说,它可以在实时环境中对路径进行增量更新。d算法最初由sven koenig和maxim likhachev在2002年提出。
d算法的基本思想是:在一个有向图上,从起点到终点的最短路径必定是一系列连续的边,而不是一些离散的节点。因此,d算法不是从起点开始,而是从终点开始,不断向起点方向搜索路径,并根据环境的变化动态更新路径。
d算法的优势是它可以在动态环境中进行实时路径规划。当环境发生变化时,d算法可以从上一次路径的终点处重新开始搜索,避免了重新规划整个路径的开销。但是,d*算法的缺点是它需要在扩展节点时进行路径更新,这可能会导致算法的效率降低。
如果我们在给机器人做路径规划,我们采用a*算法时,当机器人遇到一个小障碍物突然挡住了他正在前进的路,那他就需要重新算一遍a*,以此来找到最佳路径,而这很没有必要,d*算法的存在就是为了解决这个重复计算的问题,在最开始求出目标路径后,把搜索过程的所有信息保存下来,等后面碰到了先验未知的障碍物时就可以利用一开始保存下来的信息快速的规划出新的路径。所以说d*算法是可以应对动态环境的。
具体学习可以看这篇文章:d-star算法简介及相关思考
%请注意,上述代码仅为示例,你可能需要定义自己的getneighbors函数来获取节点的邻居,以及根据实际应用场景定义自己的cost和heuristic函数来计算代价和启发式值。
function [path] = dstar(start, goal, obstacles)
% 初始化
gscore = inf(size(obstacles));
rhsscore = inf(size(obstacles));
parent = zeros(size(obstacles));
% 将起点添加到open列表
open = priorityqueue();
open.insert(start, heuristic(start, goal));
gscore(start) = 0;
rhsscore(start) = heuristic(start, goal);
while ~open.isempty()
% 获取open列表中具有最小估计总成本的节点
currentnode = open.pop();
% 如果当前节点是目标节点,则已找到路径
if currentnode == goal
path = reconstructpath(start, goal, parent);
return;
end
% 更新当前节点的g值
if gscore(currentnode) > rhsscore(currentnode)
gscore(currentnode) = rhsscore(currentnode);
else
gscore(currentnode) = inf;
updateneighbors(currentnode, gscore, rhsscore, parent, open, obstacles);
end
end
% 如果open列表为空但仍未找到路径,则无法到达目标节点
error('no path found!');
end
function updateneighbors(node, gscore, rhsscore, parent, open, obstacles)
neighbors = getneighbors(node, obstacles);
for i = 1:numel(neighbors)
neighbor = neighbors(i);
if neighbor ~= node
rhsscore(neighbor) = min(rhsscore(neighbor), cost(node, neighbor) + gscore(node));
if gscore(neighbor) > rhsscore(neighbor)
gscore(neighbor) = rhsscore(neighbor);
parent(neighbor) = node;
open.insert(neighbor, heuristic(neighbor, goal) + gscore(neighbor));
end
end
end
end
function path = reconstructpath(start, goal, parent)
path = [goal];
currentnode = goal;
while currentnode ~= start
currentnode = parent(currentnode);
path = [currentnode, path];
end
end
function cost = cost(node1, node2)
% 计算从node1到node2的代价,可以根据实际应用场景自定义
cost = 1;
end
function h = heuristic(node, goal)
% 估计从node到goal的启发式值,可以根据实际应用场景自定义
h = abs(goal(1) - node(1)) + abs(goal(2) - node(2));
end
(快速搜索随机树)
rrt*(rapidly-exploring random tree star)是一种用于路径规划的算法,它能够在高维、复杂的空间中找到最优路径。下面是关于rrt*的基本概念:
rrt*算法通过不断扩展树结构和优化路径,使得搜索空间中的采样点趋向于目标,并找到最优路径。它在机器人路径规划、无人机路径规划等领域具有广泛应用。
请注意,rrt* 的关键特点之一是不断优化节点之间的连接,以寻找最优路径。这意味着随着迭代次数的增加,算法将收敛到全局最优路径(在无障碍情况下),并且具有渐近最优性和一致性的特点。此外,rrt* 可以在高维、复杂的环境中进行路径规划,并且适用于自主机器人导航等领域。
后面这些算法难度较大,我也暂时没有理解透彻,后续学习清楚后会继续修改文章。
具体学习算法可以参考这两篇文章:【规划】rrt*算法图解、全局路径规划:图搜索算法介绍4
lpa*(lifelong planning a*)算法是一种用于路径规划的增量式搜索算法,旨在解决动态环境中的路径规划问题。它是a*算法的改进版本,具有以下基本概念和特点:
总之,lpa算法是一种适用于动态环境下的路径规划算法,具有增量搜索、代价地图和最优性保证等特点。它可以用于自主机器人导航、自动驾驶车辆、游戏开发和其他需要实时路径规划的应用中。
lpa*算法通过不断地选择和更新优先级队列中的节点,逐步优化代价值,直到找到一条到达目标节点的路径或者确定无法到达目标节点。在每次更新节点时,需要考虑节点的代价值和启发式函数的值来确定优先级。
在a*的基础上,延伸到了动态环境,个人觉得,与d*lite算法蛮类似的,都是动态环境,都加入了启发函数。
具体学习可以参考这篇文章:lpa* 路径搜索算法介绍
python代码实现的文章:lpa* 路径搜索算法介绍及完整代码
dlite算法是一种路径规划算法,旨在解决在动态环境中的最短路径问题。它是对d算法的改进和优化。
d*lite算法的基本概念如下:
dlite算法的优点在于它能够在动态环境中实时更新路径,并能够处理障碍物的变化。这使得它在机器人导航、无人机路径规划等领域有着广泛的应用。如果你想深入了解dlite算法的实现细节和应用示例,我建议你查阅相关的学术论文和在线资源。
就是在d算法的基础上加了个和a*算法类似的启发函数,对当前情况进行评估,从而选出最优。
具体学习可以参考这篇文章:路径规划:d*lite寻路算法详解
我们可以通过算法之间的区别来理解算法之间的关系
dijkstra算法对于带权图中任意两个节点之间的最短路径问题非常有效,但在大规模图和复杂环境中,由于需要搜索所有可达节点,其时间和空间复杂度较高。
为了解决dijkstra算法效率低的问题,a*算法作为一种启发式算法被提出。该算法在广度优先的基础上加入了一个估价函数。通过合理设计启发函数(估价函数),可以将搜索范围缩小到可能最佳路径周围的区域,从而大大减少搜索节点的数量。确保按照最小的总代价进行搜索。
(简单来说,dijkstra算法不错,但是节点多的时候,挨着搜还是太慢了,不如加个估价函数,然后先评估一下哪个地方可能最佳,直接缩小节点数量,提高效率,由此提出了a*算法)
当然,我们点与点之间的关系,不可能只有距离,有时还用一种权重去表示,这样,就有了负权边,负权边可以在某些特定情况下引入更复杂的问题,因为它们与正权边不同,可能会影响最短路径计算的结果。
对于一些最短路径算法,如dijkstra算法,其前提条件是边的权重必须为非负数。而floyd算法则可以处理带有负权边的图。
a*算法适用于在静态环境中搜索单源最短路径,但是环境是不停的变化的,比如说玩游戏的自动寻路,他不可能一直直着走,也会拐弯,需要避障,这是就提出了在动态环境下进行路径规划的d*算法。d*算法是增量式的,d算法不是从起点开始,而是从终点开始,不断向起点方向搜索路径,并根据环境的变化动态更新路径,但是,d*算法需要提前获取一条路径进行参考,并且在动态环境中需要实时响应变化,可能会受到计算和存储开销的限制。d*算法适用于在动态环境中进行路径重新规划。
但我们也能看出来,d*算法为了避障,每次更新都会遍历整个路径,可能导致较高的计算复杂度。对于大规模环境或频繁更新路径的情况,性能可能会有所下降。所以d*lite算法在d算法的基础上引入了启发式函数和优先队列,以减少不必要的计算量和提高搜索效率。通过使用与a*类似的启发式函数,d*lite算法能够更好地选择节点进行扩展,从而优化路径规划的质量和性能。
lpa*算法是基于a*算法的扩展,用于解决动态环境下的路径规划问题。它通过维护节点的当前代价值和参考代价值,以及一个更新列表,通过多次迭代搜索和增量更新策略来实现路径的快速更新。lpa算法和d*算法都是增量式路径规划算法,用于处理动态环境下的路径更新问题。相比于d*算法,lpa算法引入了参考代价值和更新列表,采用多次迭代搜索和增量更新策略,更加高效地进行路径更新。具体选择哪种算法应根据具体问题需求和环境特点进行评估。
rrt算法适用于在复杂、高维空间中的路径规划。
floyd算法适合找寻任意两点之间的最短路径。
dijkstra算法(挨着搜太慢)——>a*算法(可以通过估价函数,找到最合适的点开始,但只能在静态环境)——>lpa*算法(可以在动态环境搜寻最短路径)
d*算法(可以在动态环境搜寻最短路径,但他也是遍历一遍,计算量太大)——>d*lite算法(加入和a*一样的估价函数,进行评估,更好地选择节点进行扩展)
如有侵权,请联系删除,多谢!本文只作为学习经验分享,无盈利。
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论