在网图和非网图中,最短路径的含义是不同的。由于非网图它没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径;而对于网图来说,最短路径,是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。
一、迪杰斯特拉( Dijkstra )算法
Dijkstra算法用于构建单源点的最短路径—,即图中某个点到任何其他点的距离都是最短的。例如,构建地图应用时查找自己的坐标离某个地标的最短距离。可以用于有向图,但是不能存在负权值。

我们以上图为例,通俗点说,这个迪杰斯特拉(Dijkstra) 算法,它并不是一下子求出了v0到v8的最短路径,而是一步步求出它们之间顶点的最短路径,过程中都是基于已经求出的最短路径的基础上,求得更远顶点的最短路径,最终得到你要的结果。
Dijkstra算法设置一个集合S记录已求得的最短路径的顶点。
在构造的过程中还设置了个辅助数组:
dist[]:记录从源点v0到其他各顶点当前的最短路径长度,它的初态为:若从v0到vi;有弧,则dist[i]为弧上的权值;否则置dist[i]为∞。

使用邻接矩阵或者带权的邻接表表示时,时间复杂度为O(V^2)。
完整代码(求一个点与各个点之间的最短路径)
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define MaxInt 32767 //表示极大值
#define MVNum 100 //最大顶点数
#define OK 1
typedef char VerTexType;
typedef int ArcType;
typedef int status;
typedef int OtherInfo; //和边相关的信息
typedef struct
{
char vexs[100];
int arcs[100][100];
int vexnum,arcnum;
}AMGraph;
status LocateVex(AMGraph G,VerTexType u)
{
int i;
for(i=0;i<G.vexnum;i++)
if(u==G.vexs[i]) return i;
return -1;
}
//邻接矩阵表示法
status CreateUDN(AMGraph &G)
{
cout <<"请输入总顶点数,总边数中间以空格隔开:";
cin>>G.vexnum>>G.arcnum;
cout << "输入点的名称 " <<endl;
for(int i=0;i<G.vexnum;i++)
cin>>G.vexs[i];
for(int i=0;i<G.vexnum;i++) //初始化邻接矩阵,边的权值均为Maxint
for(int j=0;j<G.vexnum;j++)
G.arcs[i][j]=MaxInt;
for(int k=0;k<G.arcnum;k++) //构造邻接矩阵
{
char v1,v2;
int w;
cin>>v1>>v2>>w; //输入一条边依附的顶点及权值
int i=LocateVex(G,v1);
int j=LocateVex(G,v2); //确定v1,v1在G中的位置,即顶点数组的下标
G.arcs[i][j]=w; //边<v1,v2>的权值置为w
G.arcs[j][i]=G.arcs[i][j]; //置<v1,v2>的对称边<v2,v1>的权值为w
}
return OK;
}
void ShortestPath_DTJ(AMGraph G,int v0){
int n=G.vexnum;//顶点数
int S[n],Path[n],i,v,w,D[n],min,sum;
for(int v=0;v<n;v++){
S[v]=0;D[v]=G.arcs[v0][v];//S[i]=1表示点已知
if(D[v]<MaxInt) //有弧
Path[v]=v0; //点的前驱
else Path[v]=-1;
}
S[v0]=1;D[v0]=0;
//初始化结束
for( i=1;i<n;i++){
min=MaxInt;
for( w=0;w<n;w++){
if(!S[w]&&D[w]<min)
v=w;min=D[w];
}
S[v]=1;
for(w=0;w<n;w++){
if(!S[w]&&(D[v]+G.arcs[v][w])<D[w]){
D[w]=D[v]+G.arcs[v][w];
Path[w]=v;
}
}
}
for (int i=0;i<n;i++)
cout<<G.vexs[v0]<<"---->"<<G.vexs[i]<<":"<<D[i]<<endl;
cout<<D[4];
}
int main(){
AMGraph G;
CreateUDN(G);
ShortestPath_DTJ(G,0);
return 0;
}
/*
5 7
0 1 2 3 4
0 1 10
0 2 3
0 3 20
1 3 5
2 1 2
2 4 15
3 4 11
结果:18
*/
二、弗洛伊德( Floyd )算法
Floyd算法相对于Dijkstra算法来说,可以解决多源最短路径问题(即可以从任意一个点到任意一个点),可应用于地图导航走最短路径、为各城市修建最短路径的通信网(节省成本)等问题,时间复杂度是O(n3)
优点:比较容易容易理解,可以算出任意两个节点之间的最短距离,代码编写简单。
缺点:时间复杂度比较高(n3),不适合计算大量数据,当数据稍微大点儿的时候就可以选择其他的算法来解决问题了,不然也会是超时。
Floyd算法与Dijkstra算法的不同
1.Floyd算法是求任意两点之间的距离,是多源最短路,而Dijkstra(迪杰斯特拉)算法是求一个顶点到其他所有顶点的最短路径,是单源最短路。
2.Floyd算法属于动态规划,我们在写核心代码时候就是相当于推dp状态方程,Dijkstra(迪杰斯特拉)算法属于贪心算法。
3.Dijkstra算法时间复杂度一般是o(n^2),Floyd算法时间复杂度是o(n^3),Dijkstra(迪杰斯特拉)算法比Floyd算法块。
Floyd算法可以算带负权的,而Dijkstra(迪杰斯特拉)算法是不可以算带负权的。并且Floyd算法不能算负权回路。
原理:
假设有向图G=(V,E)采用邻接矩阵存储。设置一个二维数组A用于存放当前顶点之间的最短路径长度,分量A[i][j]表示当前顶点i -> j的最短路径长度。然后,每次添加一个顶点,同时对A的数组进行筛选优化,期间会产生k个A数组。Ak[i][j]数组代表着从考虑0 -> k的i -> j 的最小距离,当k 等于全部顶点数的时候,就是已经找出了i -> j 的最短距离。
具体的实现手段(算法思想)
1、每一个顶点v,与任意一个顶点队(i,j),其中i≠j,v≠i,v≠j
如果存在A[i][j] > A[v][j] + A[i][v]
则将A[i][j]的值换为:A[v][j] + A[i][v],同时path[i][j]的值也换为v
2、然后依此对每一个顶点进行上述操作
3、最后得到path数组的值,就是咱们需要的最短路径的顶点坐标,再根据顶点,查找对应的A数组的值(权值),就能得到所谓的最短路径
4、最终俩个数组的意义
二维数组A:对应的是更新过后的俩点之间最短路径的一个权值
二维数组Path:对应的是更新过后俩点之间的最短路径所经历的点坐标
A[i][j] > A[v][j] + A[i][v]这个公式的目的就是求出最短的那个路径,比如在
i=1,j=2,v=3的时候,只要上述的比较公式成立,就证明了目前1到2的最短路径为1->3->2,而不是直接的1->2
完整代码(求每个顶点之间的最短路径)
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
#define MaxVertexNum 100
#define INF 32767
typedef struct
{
char vertex[MaxVertexNum];
int edges[MaxVertexNum][MaxVertexNum];
int n,e;
}MGraph;
void CreateMGraph(MGraph &G)
{
int i,j,k,p;
cout << "请输入顶点数和边数:";
cin >> G.n >> G.e;
cout << "请输入顶点元素:";
for(i = 0;i < G.n;i++)
cin >> G.vertex[i];
for(i = 0;i < G.n;i++)
for(j = 0;j < G.n;j++)
{
G.edges[i][j] = INF;
if(i == j)
G.edges[i][j] = 0;
}
for(k = 0;k < G.e;k++)
{
cout << "请输入第" << k+1 << "条弧头弧尾序号和相应的权值:";
cin >> i >> j >> p;
G.edges[i][j] = p;
}
}
void Ppath(MGraph &G,int path[][MaxVertexNum],int i,int j)
{
int k;
k = path[i][j];
if (k == -1)
return;
Ppath(G,path,i,k);
printf("%c",G.vertex[k]);
Ppath(G,path,k,j);
}
void Dispath(MGraph &G,int A[][MaxVertexNum],int path[][MaxVertexNum],int n)
{
int i,j;
for(i = 0;i < n;i++)
for(j = 0;j < n;j++)
{
if(A[i][j] == INF)
{
if(i != j)
printf("从%d到%d没有路径\n",i,j);
}
else
{
printf("从%c到%c=>路径长度:%d 路径:",G.vertex[i],G.vertex[j],A[i][j]);
printf("%c",G.vertex[i]);
Ppath(G,path,i,j);
printf("%c\n",G.vertex[j]);
}
}
}
void Floyd(MGraph &G)
{
int i,j,k;
int A[MaxVertexNum][MaxVertexNum];
int path[MaxVertexNum][MaxVertexNum];
for(i = 0;i < G.n;i++)
for(j = 0;j < G.n;j++)
{
A[i][j] = G.edges[i][j];
path[i][j] = -1;
}
for(k = 0;k < G.n;k++)
for(i = 0;i < G.n;i++)
for(j = 0;j < G.n;j++)
if(A[i][j] > A[i][k] + A[k][j])
{
A[i][j] = A[i][k] + A[k][j];
path[i][j] = k;
}
Dispath(G,A,path,G.n);
}
int main()
{
MGraph G;
CreateMGraph(G);
Floyd(G);
return 0;
}
