1.狄克斯特拉(Dijkstra)算法:
狄克斯特拉用于解决单源最短路径问题,即从图中的某一节点出发到任一节点的最短路径。缺陷:图中不能含有负权边
基本思路:
松弛操作:每确定到达一个节点的最短路径之后,计算途径当前节点到达其他邻接节点的路径是否为更优,如果是则更新邻接节点的路径。
图解说明:
用两个集合分别存放:1.已确定最优路径的节点极其代价(用S表示) 2.当前可达节点极其代价(用U表示)
如上所示的有权图,从0节点开始遍历计算达到每个顶点的最短路径:
则初始状态:S:(节点)0--0(代价),U:1--5 2--2 3--6
第一步:从U中选取代价最小的节点(节点2),加入S(S:0--0 2--2,U:1--5 3--6 ),计算经过节点2达到节点1 3代价是否更小,并更新U (S:0--0 2--2 , U:1--3 3--5 4--7)
第二步:从U中选取代价最小的节点(节点1),加入S(S:0--0 2--2 1--3,U:3--5 4--7),计算经过节点1到达节点3 4是否代价更小,并更新U (S:0--0 2--2 1--3,U:4--4 3--5)
第三步:从U中选取代价最小的节点(节点3),加入S(S:0--0 2--2 1--3 3--5 ,U:4--7),计算经过节点3到达节点4是否代价更小,并更新U (S:0--0 2--2 1--3 3--5 ,U:4--7)
第四步:从U中选取代价最小的节点(节点4),加入S (S:0--0 2--2 1--3 3--5 4--7),至此所有节点的最短路径计算完毕
对于路径规划:
dijkstra应用于路径规划(给出起点终点计算路径)中,从起点出发使用dijkstra开始遍历,当终点加入到集合S中时即找到了最短路径。但是dijkstra在遍历的过程中始终计算的是与起点的距离,目标点的方向相当于未知,当目标点加入到S(close list)中时,相当于遍历了与目标点同深度的所有节点(以起始点为圆心,目标点深度为半径做圆),即便采用最小堆来实现算法时间复杂度任为O(ElogE),E为节点数。A*在dijkstra基础上做了改进
A*dijkstra
A*算法的改进之处在于:在计算代价时不仅仅使用当前节点到起点的路径,还加入了当前节点到目标点的距离(一般采用曼哈顿距离或者欧氏距离)。这样使得当目标点加入到U(close list)中时,遍历的范围是以起点和终点为焦点的椭圆,算法时间复杂度为O(KlogE),K<E
2.弗洛伊德算法(Floyd)
Floyd的应用场景是APSP(all-point-shortest-path)问题,即所有节点两两之间的最短路径。
基本思路:
核心思路还是松弛操作,以图中所有节点为中转节点进行遍历,如果途径该节点的能够减少两节点之间的路径,则更新他们的权值(最短路径)
算法实现:
我们使用邻接矩阵来实现图的基本表示(不懂邻接矩阵戳这里图论基础),初始化邻接矩阵时不相邻的节点权值用无穷大表示,核心代码如下:
for(int k=0;k<size;k++) //该层遍历表示中转节点
{
for(int i=0;i<size;i++)
{
for(int j=0;j<size;j++)
{
if(graph[i][j]>graph[i][k]+graph[k][j]) //途径当前中转节点是否会减少i,j之间的最短路径
graph[i][j]=graph[i][k]+graph[k][j];
}
}
}
有两个需要注意的地方:1.中转节点的循环一定要放在最外层 2.如果使用数组类型最大值初始化非邻接节点,在判断相加时可能会导致算术溢出
3.对比
在解决APSP问题时,也可以直接使用Dijkstra算法进行两两查询,算法复杂度O(),Floyd算法时间复杂度(
),所以在顶点数量较少的稠密图中使用Floyd效率会更高一些