① djstl算法
定义Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN,
CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权边。
问题描述在无向图
G=(V,E) 中,假设每条边 E[i] 的长度为 w[i],找到由顶点 V0 到其余各点的最短路径。(单源最短路径)
编辑本段迪杰斯特拉算法迪杰斯特拉(Dijkstra)算法思想
按路径长度递增次序产生最短路径算法:
把V分成两组:
(1)S:已求出最短路径的顶点的集合
(2)V-S=T:尚未确定最短路径的顶点集合
将T中顶点按最短路径递增的次序加入到S中,
保证:(1)从源点V0到S中各顶点的最短路径长度都不大于
从V0到T中任何顶点的最短路径长度
(2)每个顶点对应一个距离值
S中顶点:从V0到此顶点的最短路径长度
T中顶点:从V0到此顶点的只包括S中顶点作中间
顶点的最短路径长度
依据:可以证明V0到T中顶点Vk的最短路径,或是从V0到Vk的
直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和
(反证法可证)
求最短路径步骤
算法步骤如下:
1. 初使时令 S={V0},T={其余顶点},T中顶点对应的距离值
若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值
若不存在<V0,Vi>,d(V0,Vi)为∝
2. 从T中选取一个其距离值为最小的顶点W且不在S中,加入S
3. 对S中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的
距离值缩短,则修改此距离值
重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止
编辑本段迪杰斯特拉算法的原理首先,引进一个辅助向量D,它的每个分量D表示当前所找到的从始点v到每个终点vi的最短路径的长度。如D[3]=2表示从始点v到终点3的路径相对最小长度为2。这里强调相对就是说在算法过程中D的值是在不断逼近最终结果但在过程中不一定就等于最短路径长度。它的初始状态为:若从v到vi有弧,则D为弧上的权值;否则置D为∞。显然,长度为
D[j]=Min{D | vi∈V} 的路径就是从v出发的长度最短的一条最短路径。此路径为(v,vj)。
那么,下一条长度次短的最短路径是哪一条呢?假设该次短路径的终点是vk,则可想而知,这条路径或者是(v,vk),或者是(v,vj,vk)。它的长度或者是从v到vk的弧上的权值,或者是D[j]和从vj到vk的弧上的权值之和。
一般情况下,假设S为已求得最短路径的终点的集合,则可证明:下一条最短路径(设其终点为X)或者是弧(v,x),或者是中间只经过S中的顶点而最后到达顶点X的路径。因此,下一条长度次短的最短路径的长度必是D[j]=Min{D
| vi∈V-S} 其中,D或者是弧(v,vi)上的权值,或者是D[k](vk∈S)和弧(vk,vi)上的权值之和。 迪杰斯特拉算法描述如下:
1)arcs表示弧上的权值。若不存在,则置arcs为∞(在本程序中为MAXCOST)。S为已找到从v出发的最短路径的终点的集合,初始状态为空集。那么,从v出发到图上其余各顶点vi可能达到的最短路径长度的初值为D=arcs[Locate
Vex(G,v),i] vi∈V 2)选择vj,使得D[j]=Min{D | vi∈V-S} 3)修改从v出发到集合V-S上任一顶点vk可达的最短路径长度。
编辑本段迪杰斯特拉算法C#程序public class Edge
{
public string StartNodeID ;
public string EndNodeID ;
public double Weight ; //权值,代价
} 节点则抽象成Node类,一个节点上挂着以此节点作为起点的“出边”表。
public class Node
{
private string iD ;
private ArrayList edgeList ;//Edge的集合--出边表
public Node(string id )
{
this.iD = id ;
this.edgeList = new ArrayList() ;
}
property#region property
public string ID
{
get
{
return this.iD ;
}
}
public ArrayList EdgeList
{
get
{
return this.edgeList ;
}
}
#endregion
}
在计算的过程中,我们需要记录到达每一个节点权值最小的路径,这个抽象可以用PassedPath类来表示:
/// <summary>
/// PassedPath 用于缓存计算过程中的到达某个节点的权值最小的路径
/// </summary>
public class PassedPath
{
private string curNodeID ;
private bool beProcessed ; //是否已被处理
private double weight ; //累积的权值
private ArrayList passedIDList ; //路径
public PassedPath(string ID)
{
this.curNodeID = ID ;
this.weight = double.MaxValue ;
this.passedIDList = new ArrayList() ;
this.beProcessed = false ;
}
#region property
public bool BeProcessed
{
get
{
return this.beProcessed ;
}
set
{
this.beProcessed = value ;
}
}
public string CurNodeID
{
get
{
return this.curNodeID ;
}
}
public double Weight
{
get
{
return this.weight ;
}
set
{
this.weight = value ;
}
}
public ArrayList PassedIDList
{
get
{
return this.passedIDList ;
}
}
#endregion
}
另外,还需要一个表PlanCourse来记录规划的中间结果,即它管理了每一个节点的PassedPath。
/// <summary>
/// PlanCourse 缓存从源节点到其它任一节点的最小权值路径=》路径表
/// </summary>
public class PlanCourse
{
private Hashtable htPassedPath ;
#region ctor
public PlanCourse(ArrayList nodeList ,string originID)
{
this.htPassedPath = new Hashtable() ;
Node originNode = null ;
foreach(Node node in nodeList)
{
if(node.ID == originID)
{
originNode = node ;
}
else
{
PassedPath pPath = new PassedPath(node.ID) ;
this.htPassedPath.Add(node.ID ,pPath) ;
}
}
if(originNode == null)
{
throw new Exception("The origin node is not exist !")
;
}
this.InitializeWeight(originNode) ;
}
private void InitializeWeight(Node originNode)
{
if((originNode.EdgeList == null)
||(originNode.EdgeList.Count == 0))
{
return ;
}
foreach(Edge edge in originNode.EdgeList)
{
PassedPath pPath = this[edge.EndNodeID] ;
if(pPath == null)
{
continue ;
}
pPath.PassedIDList.Add(originNode.ID) ;
pPath.Weight = edge.Weight ;
}
}
#endregion
public PassedPath this[string nodeID]
{
get
{
return (PassedPath)this.htPassedPath[nodeID] ;
}
}
}
在所有的基础构建好后,路径规划算法就很容易实施了,该算法主要步骤如下:
(1)用一张表(PlanCourse)记录源点到任何其它一节点的最小权值,初始化这张表时,如果源点能直通某节点,则权值设为对应的边的权,否则设为double.MaxValue。
(2)选取没有被处理并且当前累积权值最小的节点TargetNode,用其边的可达性来更新到达其它节点的路径和权值(如果其它节点
经此节点后权值变小则更新,否则不更新),然后标记TargetNode为已处理。
(3)重复(2),直至所有的可达节点都被处理一遍。
(4)从PlanCourse表中获取目的点的PassedPath,即为结果。
下面就来看上述步骤的实现,该实现被封装在RoutePlanner类中:
/// <summary>
/// RoutePlanner 提供图算法中常用的路径规划功能。
/// 2005.09.06
/// </summary>
public class RoutePlanner
{
public RoutePlanner()
{
}
#region Paln
//获取权值最小的路径
public RoutePlanResult Paln(ArrayList nodeList ,string
originID ,string destID)
{
PlanCourse planCourse = new PlanCourse(nodeList
,originID) ;
Node curNode = this.GetMinWeightRudeNode(planCourse
,nodeList ,originID) ;
#region 计算过程
while(curNode != null)
{
PassedPath curPath = planCourse[curNode.ID] ;
foreach(Edge edge in curNode.EdgeList)
{
PassedPath targetPath = planCourse[edge.EndNodeID] ;
double tempWeight = curPath.Weight + edge.Weight ;
if(tempWeight < targetPath.Weight)
{
targetPath.Weight = tempWeight ;
targetPath.PassedIDList.Clear() ;
for(int i=0 ;i<curPath.PassedIDList.Count ;i++)
{
targetPath.PassedIDList.Add(curPath.PassedIDList.ToString())
;
}
targetPath.PassedIDList.Add(curNode.ID) ;
}
}
//标志为已处理
planCourse[curNode.ID].BeProcessed = true ;
//获取下一个未处理节点
curNode = this.GetMinWeightRudeNode(planCourse
,nodeList ,originID) ;
}
#endregion
//表示规划结束
return this.GetResult(planCourse ,destID) ;
}
#endregion
#region private method
#region GetResult
//从PlanCourse表中取出目标节点的PassedPath,这个PassedPath即是规划结果
private RoutePlanResult GetResult(PlanCourse
planCourse ,string destID)
{
PassedPath pPath = planCourse[destID] ;
if(pPath.Weight == int.MaxValue)
{
RoutePlanResult result1 = new RoutePlanResult(null
,int.MaxValue) ;
return result1 ;
}
string[] passedNodeIDs = new
string[pPath.PassedIDList.Count] ;
for(int i=0 ;i<passedNodeIDs.Length ;i++)
{
passedNodeIDs = pPath.PassedIDList.ToString() ;
}
RoutePlanResult result = new
RoutePlanResult(passedNodeIDs ,pPath.Weight) ;
return result ;
}
#endregion
#region GetMinWeightRudeNode
//从PlanCourse取出一个当前累积权值最小,并且没有被处理过的节点
private Node GetMinWeightRudeNode(PlanCourse
planCourse ,ArrayList nodeList ,string originID)
{
double weight = double.MaxValue ;
Node destNode = null ;
foreach(Node node in nodeList)
{
if(node.ID == originID)
{
continue ;
}
PassedPath pPath = planCourse[node.ID] ;
if(pPath.BeProcessed)
{
continue ;
}
if(pPath.Weight < weight)
{
weight = pPath.Weight ;
destNode = node ;
}
}
return destNode ;
}
#endregion
#endregion
}
编辑本段迪杰斯特拉算法pascal程序type bool=array[1..10]of
boolean;
arr=array[0..10]of integer;
var a:array[1..10,1..10]of integer;
//存储图的邻接数组,无边为10000
c,d,e:arr; //c为最短路径数值,d为各点前趋,
t:bool; //e:路径,t为辅助数组
i,j,n,m:integer;
inf,outf:text;
////////////////////////////////////////////////////////////////////////////////
procere init; //不同题目邻接数组建立方式不一样
begin
assign(inf,'dijkstra.in');
assign(outf,'dijkstra.out');
reset(inf); rewrite(outf);
read(inf,n);
for i:=1 to n do
for j:=1 to n do
begin
read(inf,a[i,j]);
if a[i,j]=0 then a[i,j]:=10000;
end;
end;
////////////////////////////////////////////////////////////////////////////////
procere dijkstra(qi:integer; t:bool; var c{,d}:arr);
//qi起点,{}中为求路径部
var i,j,k,min:integer; //分,不需求路径时可以不要
begin //t数组一般在调用前初始
t[qi]:=true; //化成false,也可将部分点
{for i:=1 to n do d[i]:=qi; d[qi]:=0; }
//初始化成true以回避这些点
for i:=1 to n do c[i]:=a[qi,i];
for i:=1 to n-1 do
begin
min:=10001;
for j:=1 to n do
if (c[j]<min)and(not(t[j])) then begin k:=j;
min:=c[j];end;
t[k]:=true;
for j:=1 to n do
if (c[k]+a[k,j]<c[j])and(not(t[j])) then
begin
c[j]:=c[k]+a[k,j]; {d[j]:=k;}
end;
end;
end;
////////////////////////////////////////////////////////////////////////////////
procere make(zh:integer; d:arr; var e:arr);
//生成路径,e[0]保存路径
var i,j,k:integer; //上的节点个数
begin
i:=0;
while d[zh]<>0 do
begin
inc(i);e[i]:=zh;zh:=d[zh];
end;
inc(i);e[i]:=qi; e[0]:=I;
end;
主程序调用:求最短路径长度:初始化t,然后dijkstra(qi,t,c,d)
求路径:make(m,d,e) ,m是终点
编辑本段Dijkstra算法的堆优化(PASCAL实现)一、思考
我们可以发现,在实现步骤时,效率较低(需要O(n),使总复杂度达到O(n^2)。对此可以考虑用堆这种数据结构进行优化,使此步骤复杂度降为O(log(n))(总复杂度降为O(n
log(n))。
二、实现
1. 将与源点相连的点加入堆,并调整堆。
2. 选出堆顶元素u(即代价最小的元素),从堆中删除,并对堆进行调整。
3. 处理与u相邻的,未被访问过的,满足三角不等式的顶点
1):若该点在堆里,更新距离,并调整该元素在堆中的位置。
2):若该点不在堆里,加入堆,更新堆。
4. 若取到的u为终点,结束算法;否则重复步骤2、3。
三、代码
procere Dijkstra;
var
u,v,e,i:longint;
begin
fillchar(dis,sizeof(dis),$7e); //距离
fillchar(Inh,sizeof(Inh),false); //是否在堆中
fillchar(visit,sizeof(visit),false); //是否访问过
size:=0;
e:=last[s];
while e<>0 do //步骤1
begin
u:=other[e];
if not(Inh[u]) then //不在堆里
begin
inc(size);
heap[size]:=u;
dis[u]:=cost[e];
Loc[u]:=size; //Loc数组记录元素在堆中的位置
Inh[u]:=true;
Shift_up(Loc[u]); //上浮
end
else
if cost[e]<dis[u] then //在堆里
begin
dis[u]:=cost[e];
Shift_up(Loc[u]);
Shift_down(Loc[u]);
end;
e:=pre[e];
end;
visit[s]:=true;
while true do
begin
u:=heap[1]; //步骤2
if u=t then break; //步骤4
visit[u]:=true;
heap[1]:=heap[size];
dec(size);
Shift_down(1);
e:=last[u];
while e<>0 do //步骤3
begin
v:=other[e];
if Not(visit[v]) and (dis[u]+cost[e]<dis[v]) then
//与u相邻的,未被访问过的,满足三角不等式的顶点
if Inh[v] then //在堆中
begin
dis[v]:=dis[u]+cost[e];
Shift_up(Loc[v]);
Shift_Down(Loc[v]);
end
else //不再堆中
begin
inc(size);
heap[size]:=v;
dis[v]:=dis[u]+cost[e];
Loc[v]:=size;
Inh[v]:=true;
Shift_up(Loc[v]);
end;
e:=pre[e];
end;
end;
writeln(dis[t]);
end;
http://ke..com/view/7839.htm
http://ke..com/view/1939816.htm
② (4)动力学约束下的路径规划
运动学上的约束,比如避障,动力学约束,比如速度,加速度,等
在考虑上述条件的情况下,是不能将机器人简单的考虑为一个质点,进行路径规划的
纯学院派的路径规划是不在前端考虑的,但是当动力学约束非常复杂的时候,完全依赖后端进行优化是不现实的。
我们希望点之间的连线是满足动力学
正向方式:离散机器人控制空间,产生很多路径
反向方式:离散机器人状态空间,寻找路径
最开始基于图的搜索算法其实就是对机器人的控制空间的离散化,将机器人的控制空间进行四离散或者八离散
基于采样的搜索算法其实就是对状态空间的离散化,将机器人的状态离散为每个点
首先建立描述机器人状态的微分方程,s' = f(s,u)
首先知道机器人的初始状态s0
1、离散化控制空间,给系统一个固定的u激励,保持一个时间T,正向模拟系统
知道S0,给定u和T,进行模拟,积分就好了,但是没有目标导向,规划效率比较低
2、离散化状态空间,选择一个新状态Sf,从Sf和S0解析出一个轨迹(u,T),在求解困难的情况下,可以固定时间T,求解u,反向求解系统,难以实现特定的算法,但是效率很高,任务导向性很高
控制空间离散化,从树里选择一点,然后衍生lattice grauph,给定时间,再去往前积分,选择路径
状态空间离散化,选择一点,反算是如何到达的
③ 基于神经网络的路径规划算法,怎样判断点是否在障碍物内部的
遗传算法在很多领域都得到应用;从神经网络研究的角度上考虑,最关心的是遗传算法在神经网络的应用。在遗传算法应用中,应先明确其特点和关键问题,才能对这种算法深入了解,灵活应用,以及进一步研究开发。一、遗传算法的特点1.遗传算法从问
④ 基于激光雷达的SLAM和路径规划算法研究与实现
本文仅供学习使用,并非商业用途,全文是针对哈尔滨工业大学刘文之的论文《移动机器人的路径规划与定位技术研究》进行提炼与学习。论文来源中国知网,引用格式如下:
[1]刘文之. 基于激光雷达的SLAM和路径规划算法研究与实现[D].哈尔滨工业大学,2018.
相关坐标系转换原理已经在前一篇文章写完了,直接上转换方程。
这里他的运动模型选择的是基于里程计的运动模型,还有一种基于速度的运动模型,其实都差不多,整体思想都一样。里程计是通过计算一定时间内光电编码器输出脉冲数来估计机器人运动位移的装置,主要是使用光电码盘。根据光电码盘计算出此时轮子的速度,然后通过已知的轮子半径来获得单位时间 每个轮子 的位移增量。
高等数学可知单位时间位移增量就是速度,对速度在一定时间上进行积分就得到这一段时间所走过的路程。
根据上图,我们可以求出来机器人航向角角速度、圆弧运动半径和机器人角度变化量,由此可以解的机器人在当前时刻的位姿。
实际上也是有误差,所以单独依靠里程计会与实际结果产生较大误差,所以必须引入其他的外部传感器对外部环境的观测来修正这些误差,从而提高定位精度。
首先肯定需要将激光雷达所测得的端点坐标从极坐标、机器人坐标中转换到世界坐标中。
这张略过,暂时不需要看这个
路径规划算法介绍:
因为该算法会产生大量的无用临时途径,简单说就是很慢,所以有了其他算法。
了解两种代价之后,对于每一个方块我们采用预估代价与当前路径代价相加的方法,这样可以表示每一个路径点距离终点的距离。在BFS搜索过程的基础上,优先挑选总代价最低的那个路径进行搜索,就可以少走不少弯路。(算法讲解 https://www.bilibili.com/video/BV1bv411y79P?from=search&seid=3623681329596549549 )
在局部路径规划算法之中,我们选用DWA算法(dynamic window approach),又叫动态窗口法。动态窗口法主要是在速度(v, w)空间中采样多组速度,并模拟机器人在这些速度下一定时间内的轨迹。在得到多组轨迹后,对这些轨迹进行评价,选取最优的轨迹所对应的速度来驱动机器人运动。
state sampling就是按照之前给出的全局路径规划,无论是Dijkstra还是A* 都可以方便的得到state sampling,DWA算法所需要提前建立的action sampling有两种:
但是无论是什么情况,上述所做的工作就是把机器人的位移转化到世界坐标中来,而不是机器人坐标系。速度采样结束之后,只需要对小车的轨迹进行评判,就可以得到最优解了。下面介绍速度采样的办法。
对速度进行采样一般有以下三个限制:
当确定了速度范围之后,就需要根据速度分辨率来对小车速度离散化,在每一时刻将小车在不同直线速度角速度组合下所即将要行驶的距离都可视化出来。
其中每一条轨迹都是很多小直线连接起来的。
需要用评价函数来对上述轨迹进行选择,选择最适合的轨迹
最后为了让三个参数在评价函数里所发挥的作用均等,我们使用归一化处理来计算权重。
算法流程整体如下:
⑤ 遗传算法路径规划是什么原理
遗传算法有相当大的引用。遗传算法在游戏中应用的现状在遗传编码时, 一般将瓦片的坐标作为基因进行实数编码, 染色体的第一个基因为起点坐标, 最后一个基因为终点坐标, 中间的基因为路径经过的每一个瓦片的坐标。在生成染色体时, 由起点出发, 随机选择当前结点的邻居节点中的可通过节点, 将其坐标加入染色体, 依此循环, 直到找到目标点为止, 生成了一条染色体。重复上述操作, 直到达到指定的种群规模。遗传算法的优点:1、遗传算法是以决策变量的编码作为运算对象,可以直接对集合、序列、矩阵、树、图等结构对象进行操作。这样的方式一方面有助于模拟生物的基因、染色体和遗传进化的过程,方便遗传操作算子的运用。另一方面也使得遗传算法具有广泛的应用领域,如函数优化、生产调度、自动控制、图像处理、机器学习、数据挖掘等领域。2、遗传算法直接以目标函数值作为搜索信息。它仅仅使用适应度函数值来度量个体的优良程度,不涉及目标函数值求导求微分的过程。因为在现实中很多目标函数是很难求导的,甚至是不存在导数的,所以这一点也使得遗传算法显示出高度的优越性。3、遗传算法具有群体搜索的特性。它的搜索过程是从一个具有多个个体的初始群体P(0)开始的,一方面可以有效地避免搜索一些不必搜索的点。另一方面由于传统的单点搜索方法在对多峰分布的搜索空间进行搜索时很容易陷入局部某个单峰的极值点,而遗传算法的群体搜索特性却可以避免这样的问题,因而可以体现出遗传算法的并行化和较好的全局搜索性。4、遗传算法基于概率规则,而不是确定性规则。这使得搜索更为灵活,参数对其搜索效果的影响也尽可能的小。5、遗传算法具有可扩展性,易于与其他技术混合使用。以上几点便是遗传算法作为优化算法所具备的优点。遗传算法的缺点:遗传算法在进行编码时容易出现不规范不准确的问题。
⑥ 机器人路径规划算法是什么
机器人路径规划算法是 路径规划的目的是在给定起点和目标点的空间里规划出一条从起点到目标点的无碰撞路径。
移动机器人的路径规划,就是移动机器人在所处的环境中寻找到一条从起始点到目标点的无碰路径,尤其是移动机器人在没有人为干预的情况下的自主运动,这就需要各种智能算法融入到机器人自身控制系统中,使得移动机器人自主做出判断和决策。
⑦ 关于时间依赖的最短路径算法
Dijkstra 最短路径算法的一种高效率实现*
随着计算机的普及以及地理信息科学的发展,GIS因其强大的功能得到日益广泛和深入的应用。网络分析作为GIS最主要的功能之一,在电子导航、交通旅游、城市规划以及电力、通讯等各种管网、管线的布局设计中发挥了重要的作用,而网络分析中最基本最关键的问题是最短路径问题。最短路径不仅仅指一般地理意义上的距离最短,还可以引申到其他的度量,如时间、费用、线路容量等。相应地,最短路径问题就成为最快路径问题、最低费用问题等。由于最短路径问题在实际中常用于汽车导航系统以及各种应急系统等(如110报警、119火警以及医疗救护系统),这些系统一般要求计算出到出事地点的最佳路线的时间应该在1 s~3 s内,在行车过程中还需要实时计算出车辆前方的行驶路线,这就决定了最短路径问题的实现应该是高效率的。其实,无论是距离最短、时间最快还是费用最低,它们的核心算法都是最短路径算法。经典的最短路径算法——Dijkstra算法是目前多数系统解决最短路径问题采用的理论基础,只是不同系统对Dijkstra算法采用了不同的实现方法。
据统计,目前提出的此类最短路径的算法大约有17种。F.Benjamin Zhan等人对其中的15种进行了测试,结果显示有3种效果比较好,它们分别是:TQQ(graph growth with two queues)、DKA (the Dijkstra's algorithm implemented with approximate buckets) 以及 DKD (the Dijkstra�s algorithm implemented with double buckets ),这些算法的具体内容可以参见文献〔1〕。其中TQQ算法的基础是图增长理论,较适合于计算单源点到其他所有点间的最短距离;后两种算法则是基于Dijkstra的算法,更适合于计算两点间的最短路径问题〔1〕。总体来说,这些算法采用的数据结构及其实现方法由于受到当时计算机硬件发展水平的限制,将空间存储问题放到了一个很重要的位置,以牺牲适当的时间效率来换取空间节省。目前,空间存储问题已不是要考虑的主要问题,因此有必要对已有的算法重新进行考虑并进行改进,可以用空间换时间来提高最短路径算法的效率。
1 经典Dijkstra算法的主要思想
Dijkstra算法的基本思路是:假设每个点都有一对标号 (dj, pj),其中dj是从起源点s到点j的最短路径的长度 (从顶点到其本身的最短路径是零路(没有弧的路),其长度等于零);pj则是从s到j的最短路径中j点的前一点。求解从起源点s到点j的最短路径算法的基本过程如下:
1) 初始化。起源点设置为:① ds=0, ps为空;② 所有其他点: di=∞, pi= ;③ 标记起源点s,记k=s,其他所有点设为未标记的。
2) 检验从所有已标记的点k到其直接连接的未标记的点j的距离,并设置:
dj=min〔dj, dk+lkj〕
式中,lkj是从点k到j的直接连接距离。
3) 选取下一个点。从所有未标记的结点中,选取dj 中最小的一个i:
di=min〔dj, 所有未标记的点j〕
点i就被选为最短路径中的一点,并设为已标记的。
4) 找到点i的前一点。从已标记的点中找到直接连接到点i的点j*,作为前一点,设置:
i=j*
5) 标记点i。如果所有点已标记,则算法完全推出,否则,记k=i,转到2) 再继续。
2 已有的Dijkstra算法的实现
从上面可以看出,在按标记法实现Dijkstra算法的过程中,核心步骤就是从未标记的点中选择一个权值最小的弧段,即上面所述算法的2)~5)步。这是一个循环比较的过程,如果不采用任何技巧,未标记点将以无序的形式存放在一个链表或数组中。那么要选择一个权值最小的弧段就必须把所有的点都扫描一遍,在大数据量的情况下,这无疑是一个制约计算速度的瓶颈。要解决这个问题,最有效的做法就是将这些要扫描的点按其所在边的权值进行顺序排列,这样每循环一次即可取到符合条件的点,可大大提高算法的执行效率。另外,GIS中的数据 (如道路、管网、线路等)要进行最短路径的计算,就必须首先将其按结点和边的关系抽象为图的结构,这在GIS中称为构建网络的拓扑关系 (由于这里的计算与面无关,所以拓扑关系中只记录了线与结点的关系而无线与面的关系,是不完备的拓扑关系)。如果用一个矩阵来表示这个网络,不但所需空间巨大,而且效率会很低。下面主要就如何用一个简洁高效的结构表示网的拓扑关系以及快速搜索技术的实现进行讨论。
网络在数学和计算机领域中被抽象为图,所以其基础是图的存储表示。一般而言,无向图可以用邻接矩阵和邻接多重表来表示,而有向图则可以用邻接表和十字链表〔4〕 表示,其优缺点的比较见表 1。
表 1 几种图的存储结构的比较
Tab. 1 The Comparsion of Several Graph for Storing Structures
名 称 实现方法 优 点 缺 点 时间复杂度
邻接矩阵 二维数组 1. 易判断两点间的关系 占用空间大 O(n2+m*n)
2. 容易求得顶点的度
邻接表 链表 1. 节省空间 1. 不易判断两点间的关系 O(n+m)或O(n*m)
2. 易得到顶点的出度 2. 不易得到顶点的入度
十字链表 链表 1. 空间要求较小 结构较复杂 同邻接表
2.易求得顶点的出度和入度
邻接多重表 链表 1. 节省空间 结构较复杂 同邻接表
2. 易判断两点间的关系
目前,对于算法中快速搜索技术的实现,主要有桶结构法、队列法以及堆栈实现法。TQQ、DKA 以及 DKD 在这方面是比较典型的代表。TQQ虽然是基于图增长理论的,但是快速搜索技术同样是其算法实现的关键,它用两个FIFO的队列实现了一个双端队列结构来支持搜索过程〔1〕。
DKA和DKD是采用如图 1 所示的桶结构来支持这个运算,其算法的命名也来源于此。在DKA算法中,第i个桶内装有权值落在 〔b*i, (i+1)*b) 范围内的可供扫描的点,其中b是视网络中边的权值分布情况而定的一个常数。每一个桶用队列来维护,这样每个点有可能被多次扫描,但最多次数不会超过b次。最坏情况下,DKA的时间复杂度将会是O(m*b+n(b+C/b)),其中,C为图中边的最大权值。DKD将点按权值的范围大小分装在两个级别的桶内,高级别的桶保存权值较大的点,相应的权值较小的点都放在低级别的桶内,每次扫描都只针对低级别桶中的点。当然随着点的插入和删除,两个桶内的点是需要动态调整的。在DKA算法中,给每个桶一定的范围以及DKD中使用双桶,在一定程度上都是以空间换时间的做法,需要改进。
图 1 一个桶结构的示例
Fig. 1 An Example of the Bucket Data Structure
3 本文提出的Dijkstra算法实现
3.1 网络拓扑关系的建立
上面介绍的各种图的存储结构考虑了图在理论上的各种特征,如有向、无向、带权、出度、入度等。而GIS中的网络一般为各种道路、管网、管线等,这些网络在具有图理论中的基本特征的同时,更具有自己在实际中的一些特点。首先,在GIS中大多数网络都是有向带权图,如道路有单双向问题,电流、水流都有方向(如果是无向图也可归为有向图的特例),且不同的方向可能有不同的权值。更重要的一点是,根据最短路径算法的特性可以知道,顶点的出度是个重要指标,但是其入度在算法里则不必考虑。综合以上4种存储结构的优缺点, 笔者采用了两个数组来存储网络图,一个用来存储和弧段相关的数据(Net-Arc List),另一个则存储和顶点相关的数据(Net-Node Index)。Net-Arc List用一个数组维护并且以以弧段起点的点号来顺序排列,同一起点的弧段可以任意排序。这个数组类似于邻接矩阵的压缩存储方式,其内容则具有邻接多重表的特点,即一条边以两顶点表示。Net-Node Index则相当于一个记录了顶点出度的索引表,通过它可以很容易地得到此顶点的出度以及与它相连的第一条弧段在弧段数组中的位置。此外,属性数据作为GIS不可少的一部分也是必须记录的。这样,计算最佳路径所需的网络信息已经完备了。在顶点已编号的情况下,建立Net-Arc List和Net-Node Index两个表以及对Net-Arc List的排序,其时间复杂度共为O(2n+lgn),否则为O(m+2n+lgn)。这个结构所需的空间也是必要条件下最小的,记录了m个顶点以及n条边的相关信息,与邻接多重表是相同的。图 2 是采用这个结构的示意图。
3.2 快速搜索技术的实现
无论何种算法,一个基本思想都是将点按权值的大小顺序排列,以节省操作时间。前面已经提到过,这两个算法都是以时间换空间的算法,所以在这里有必要讨论存储空间问题 (这部分空间的大小依赖于点的个数及其出度)。根据图中顶点和边的个数可以求出顶点的平均出度e=m/n(m为边数,n为顶点数),这个数值代表了图的连通程度,一般在GIS的网络图中,e∈〔2,5〕。这样,如果当前永久标记的点为t个,那么,下一步需扫描点的个数就约为t~4t个。如果采用链表结构,按实际应用中的网络规模大小,所需的总存储空间一般不会超过100 K。所以完全没有必要采用以时间换空间的做法,相反以空间换时间的做法是完全可行的。在实现这部分时,笔者采用了一个FIFO队列,相应的操作主要是插入、排序和删除,插入和删除的时间复杂度都是O(1),所以关键问题在于选择一个合适的排序算法。一般可供选择的排序算法有快速排序、堆排序以及归并排序等,其实现的平均时间都为O(nlgn)。经过比较实验,笔者选择了快速排序法。另外,Visual C++提供的run-time库也提供了现成的快速排序的函数qsort( )可供使用。
图 2 基于最佳路径计算的网络拓扑表示
Fig. 2 The Presentation of the Network Topology
Used for Computing the Shortest Path
按照以上思路,笔者用Visual C++实现了吉奥之星(GeoStar)中的最佳路径模块。以北京的街道为数据(共6 313个结点,9 214条弧段(双向)),在主频为133、硬盘为1 G、内存为32 M的机器上,计算一条贯穿全城、长为155.06 km的线路,约需1 s~2 s。如图 3所示。
图 3 GeoStar中最佳路径实现示意图
ps:图片没有办法贴上去.
你可以参考《算法导论》第二版
⑧ 全局路径规划算法
全局路径规划,主要算法有
1、网格法、
2、拓扑法、
3、视图法。
⑨ 路径规划算法
强化学习比较好吧
⑩ 代码!!!--基于遗传算法在路径规划优化中的应用
遗传算法, 是人工智能的一种算法的。
以前图书馆有看到, 很多相关的书的,不要寄望于自己什么都不做,就找人家帮忙啦。