目录
一、Dijkstra算法
- Dijkstra算法:可以求带权图中一个顶点到其余各顶点的最短路径(单源最短路径)
- 基本算法步骤:
第一步:初始时,顶点集只含源点,即,顶点到自己的距离为0.顶点集包含除外其他顶点,源点到中顶点的距离为边上权值。
第二步:从中选取一个顶点,它是源点到中距离最小的一个顶点,然后把顶点加入中
第三步:以顶点作为新考虑的中间点,修改中那些从顶点到有边的顶点的最短路径长度
(中其他顶点从顶点没有边到达的顶点不需要调整)。考虑顶点的时候,从源点到顶点(属于)有如下两条路径,在这两条路径中取更短的路径,求从源点到顶点的最短路径长度= ,其中:
1.不经过顶点u的路径,路径长度为
2.从顶点u有一条边到达顶点j的路径,该路径由两段构成,其长度为
第四步:重复步骤二和步骤三,直到所有顶点都包含在中。 - 算法设计:
用数组表示集合中的元素,即对于顶点,表示它在中,表示它在中
用保存从源点到顶点的当前最短路径长度,它的初值为边上权值
用保存从源点到的最短路径,实际上保存从源点到顶点的当前最短路径中顶点的前一个顶点编号
(一)演示
(二)核心代码
void Dijkstra(MGraph G, int v)
{
int S[MAXV];//用于记录顶点是否在集合U中
int dist[MAXV];//用于保存从源点到某顶点的当前最短路径长度
int path[MAXV];//用于保存从源点到某顶点的最短路径
for (int i = 0; i < G.n; i++)//初始化
{
S[i] = 0;
}
S[v] = 1;
for (int i = 0; i < G.n; i++)
{
dist[i] = G.edges[v][i];
}
for (int j = 0; j < G.n; j++)//path[]数组初始化
{
if (S[j]==0&&G.edges[v][j] != INF && G.edges[v][j] != 0)//当v到i没有边的时候
{
path[j] = v;
}
else
{
path[j] = -1;
}
}
int u = 0;
for (int i = 0; i < G.n-1; i++)//循环向S中添加n-1个顶点
{
int min = INF;
for (int k = 0; k < G.n; k++)//选取不在S中并且具有最小距离的顶点
{
if (S[k] == 0 && dist[k] < min)
{
min = dist[k];
u = k;
}
}
S[u] = 1;
for (int i = 0; i < G.n; i++)
{
if (S[i] == 0)//仅仅调整不属于S中的顶点的最短路径长度,且需要考虑新加入S中的顶点
{
if (G.edges[u][i] + dist[u] < dist[i] && G.edges[u][i] != INF)
{
dist[i] = G.edges[u][i] + dist[u];
path[i] = u;
}
}
}
}
Disp(G, S, dist, path, v);
}
void Disp(MGraph G, int S[], int dist[], int path[],int v)
{
for (int i = 0; i < G.n; i++)
{
if (S[i] == 1 && i != v)
{
cout << "从" << G.vexs[v] << "到" << G.vexs[i] << "最短路径长度为:" << dist[i]<<endl;
}
if (S[i] == 1 && i != v)
{
int d[MAXV]={0};
int m = 0;
d[m] = i;//先存放路径上的终点
int k = path[i];
if (path[i] == -1)
{
cout << "无路径!" << endl;
}
else
{
while (k != v)
{
m++;
d[m] = k;
k = path[k];
}
m++;
d[m] = v;//添加路径上的起点
cout << d[m];//先输出起点
for (int j = m-1 ; j >= 0; j--)
{
cout << "->" << d[j];
}
cout << endl;
}
}
}
}
(三)完整代码
//Dijk.h
#pragma once
#include<iostream>
using namespace std;
#define MAXV 100
#define INF 10000
typedef int EdgeType;
typedef char VertexType;
typedef struct
{
int n, e;
EdgeType edges[MAXV][MAXV];
VertexType vexs[MAXV];
}MGraph;
void Creat(MGraph& G,int A[][MAXV],int n);//创建图的邻接矩阵
void Print(MGraph G);//打印
void Dijkstra(MGraph G, int v);//从v出发到各个顶点的最短路径
void Disp(MGraph G, int S[], int dist[], int path[],int v);//输出路径
void Dijkstra2(MGraph G, int v, int w);//从v出发到u的最短路径
void DispPath(MGraph G, int S[], int dist[], int path[], int v,int u);//输出从v到u的最短路径
//Dijks.cpp
#include"Dijk.h"
void Creat(MGraph& G, int A[][MAXV], int n)
{
G.n = n;
G.e = 0;
cout << "请依次输入顶点信息:";
for (int i = 0; i < n; i++)
{
cin >> G.vexs[i];
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
G.edges[i][j] = A[i][j];
if (A[i][j] != 0 && A[i][j] != INF)
{
G.e++;
}
}
}
}
void Print(MGraph G)
{
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
cout << G.edges[i][j] << " ";
}
cout << endl;
}
}
void Dijkstra(MGraph G, int v)
{
int S[MAXV];//用于记录顶点是否在集合U中
int dist[MAXV];//用于保存从源点到某顶点的当前最短路径长度
int path[MAXV];//用于保存从源点到某顶点的最短路径
for (int i = 0; i < G.n; i++)//初始化
{
S[i] = 0;
}
S[v] = 1;
for (int i = 0; i < G.n; i++)
{
dist[i] = G.edges[v][i];
}
for (int j = 0; j < G.n; j++)//path[]数组初始化
{
if (S[j]==0&&G.edges[v][j] != INF && G.edges[v][j] != 0)//当v到i没有边的时候
{
path[j] = v;
}
else
{
path[j] = -1;
}
}
int u = 0;
for (int i = 0; i < G.n-1; i++)//循环向S中添加n-1个顶点
{
int min = INF;
for (int k = 0; k < G.n; k++)//选取不在S中并且具有最小距离的顶点
{
if (S[k] == 0 && dist[k] < min)
{
min = dist[k];
u = k;
}
}
S[u] = 1;
for (int i = 0; i < G.n; i++)
{
if (S[i] == 0)//仅仅调整不属于S中的顶点的最短路径长度,且需要考虑新加入S中的顶点
{
if (G.edges[u][i] + dist[u] < dist[i] && G.edges[u][i] != INF)
{
dist[i] = G.edges[u][i] + dist[u];
path[i] = u;
}
}
}
}
Disp(G, S, dist, path, v);
}
void Disp(MGraph G, int S[], int dist[], int path[],int v)
{
for (int i = 0; i < G.n; i++)
{
if (S[i] == 1 && i != v)
{
cout << "从" << G.vexs[v] << "到" << G.vexs[i] << "最短路径长度为:" << dist[i]<<endl;
}
if (S[i] == 1 && i != v)
{
int d[MAXV]={0};
int m = 0;
d[m] = i;//先存放路径上的终点
int k = path[i];
if (path[i] == -1)
{
cout << "无路径!" << endl;
}
else
{
while (k != v)
{
m++;
d[m] = k;
k = path[k];
}
m++;
d[m] = v;//添加路径上的起点
cout << d[m];//先输出起点
for (int j = m-1 ; j >= 0; j--)
{
cout << "->" << d[j];
}
cout << endl;
}
}
}
}
void Dijkstra2(MGraph G, int v, int w)//从v出发到w的最短路径
{
int S[MAXV];
int dist[MAXV];
int path[MAXV];
for (int i = 0; i < G.n; i++)//初始化S[MAXV]数组
{
S[i] = 0;
}
S[v] = 1;
for (int i = 0; i < G.n; i++)//初始化dist[MAXV]数组
{
dist[i] = G.edges[v][i];
}
for (int i = 0; i < G.n-1; i++)//初始化path[MAXV]数组
{
if (G.edges[v][i] != INF && G.edges[v][i] != 0)
{
path[i] = v;
}
else
{
path[i] = -1;
}
}
int k = 0;
for (int i = 0; i < G.n-1; i++)//循环向S中添加n-1个顶点
{
int min = INF;
for (int j = 0; j < G.n; j++)//选取不在S中并且具有最小距离的顶点
{
if (S[j] == 0 && G.edges[v][j] != 0 && dist[j] < min)
{
min = dist[j];
k = j;
}
}
S[k] = 1;
if (k == w)//如果新加入集合S的顶点恰好是要找的终点,就退出循环
{
break;
}
else
{
for (int j = 0; j < G.n; j++)
{
if (S[j] == 0)//更新不属于U中的顶点的最短路径长度
{
if (G.edges[v][j] != 0 && G.edges[k][j] + dist[k] < dist[j])
{
dist[j] = G.edges[k][j] + dist[k];
path[j] = k;
}
}
}
}
}
DispPath(G, S, dist, path, v, w);
}
void DispPath(MGraph G, int S[], int dist[], int path[], int v, int w)//输出从v到w的最短路径
{
if (S[w] == 1 && w != v)
{
cout << "从" << G.vexs[v] << "到" << G.vexs[w] << "最短路径长度为:" << dist[w] << endl;
}
if (S[w] == 1 && w != v)
{
int d[MAXV];
int m = 0;
d[m] = w;
int k = path[w];
while (k != v)
{
m++;
d[m] = k;
k = path[k];
}
m++;
d[m] = v;
cout << "最短路径是:" << d[m];
for (int j = m - 1; j >= 0; j--)
{
cout << "->" << d[j];
}
}
}
//Text.cpp
#include"Dijk.h"
int main()
{
int A[][MAXV] = { {0,4,6,6,INF,INF,INF},{INF,0,1,INF,7,INF,INF},{INF,INF,0,INF,6,4,INF},{INF,INF,2,0,INF,5,INF},{INF,INF,INF,INF,0,INF,6},{INF,INF,INF,INF,1,0,8},{INF,INF,INF,INF,INF,INF,0} };
MGraph G;
Creat(G, A, 7);
cout << "图的邻接矩阵:" << endl;
Print(G);
Dijkstra(G, 0);
cout << endl;
Dijkstra2(G, 2, 6);
return 0;
}
(四)运行结果
二、Floyd算法
(一)详细介绍
(二)核心代码
void Floyd(MGraph G)//Floyd算法
{
int A[MAXV][MAXV];//保存最短路径长度
int path[MAXV][MAXV];//保存最短路径
for (int i = 0; i < G.n; i++)//初始化A[][]数组
{
for (int j = 0; j < G.n; j++)
{
A[i][j] = G.edges[i][j];
}
}
for (int i = 0; i < G.n; i++)//初始化path[][]数组
{
for (int j = 0; j < G.n; j++)
{
if (G.edges[i][j] == INF || G.edges[i][j] == 0)//i到j不存在边
{
path[i][j] = -1;
}
else
{
path[i][j] = i;//i到j存在边的时候,下标为j的顶点前驱顶点的编号是i
}
}
}
for (int k = 0; k < G.n; k++)//依次将下标从0到G.n的顶点作为中转点
{
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
if ((A[i][k] + A[k][j]) < A[i][j])//找到更短路径长度
{
A[i][j] = A[i][k] + A[k][j];//修改路径长度
path[i][j] = path[k][j];//修改下标为j的顶点的前驱顶点
//而path[k][j]存放的是恰好是从下标为k到下标为j顶点的路径中,下标为j的顶点的前驱顶点编号
}
}
}
}
DisPath(G, A, path);
/*for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
cout << path[i][j] << " ";
}
cout << endl;
}
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
cout << A[i][j] << " ";
}
cout << endl;
}*/
}
void DisPath(MGraph G, int A[][MAXV], int path[][MAXV])
{
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
if (A[i][j] != 0 && A[i][j] != INF && i != j)
{
cout << "从" << G.vexs[i] << "到" << G.vexs[j] << "最短路径长度是:" << A[i][j] << endl;
int d[MAXV];
int m = 0;
d[m] = j;//先存终点的下标
int k = path[i][j];
while (k != i && k != -1)
{
m++;
d[m] = k;
k = path[i][k];
}
m++;
d[m] = i;//存起点的下标
cout << "路径是:" << d[m];
for (int p = m - 1; p >= 0; p--)
{
cout << "->" << d[p];
}
cout << endl;
}
}
}
}
(三)完整代码
//Floyd.h
#pragma once
#include<iostream>
using namespace std;
#define MAXV 100
#define INF 10000
typedef int VertexType;
typedef int EdgeType;
typedef struct
{
int n, e;
VertexType vexs[MAXV];
EdgeType edges[MAXV][MAXV];
}MGraph;
void Creat(MGraph &G, int E[][MAXV], int n);//创建邻接矩阵
void Print(MGraph G);//打印图
void Floyd(MGraph G);//Floyd算法
void DisPath(MGraph G, int A[][MAXV], int path[][MAXV]);//打印最短路径
//Floyd.cpp
#include"Floyd.h"
void Creat(MGraph &G, int E[][MAXV], int n)
{
G.n = n;
G.e = 0;
cout << "请依次输入顶点:";
for (int i = 0; i < G.n; i++)
{
cin >> G.vexs[i];
}
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
G.edges[i][j] = E[i][j];
if (E[i][j] != 0 && E[i][j] != INF)
{
G.e++;
}
}
}
}
void Print(MGraph G)
{
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
cout << G.edges[i][j] << " ";
}
cout << endl;
}
}
void Floyd(MGraph G)//Floyd算法
{
int A[MAXV][MAXV];//保存最短路径长度
int path[MAXV][MAXV];//保存最短路径
for (int i = 0; i < G.n; i++)//初始化A[][]数组
{
for (int j = 0; j < G.n; j++)
{
A[i][j] = G.edges[i][j];
}
}
for (int i = 0; i < G.n; i++)//初始化path[][]数组
{
for (int j = 0; j < G.n; j++)
{
if (G.edges[i][j] == INF || G.edges[i][j] == 0)//i到j不存在边
{
path[i][j] = -1;
}
else
{
path[i][j] = i;//i到j存在边的时候,下标为j的顶点前驱顶点的编号是i
}
}
}
for (int k = 0; k < G.n; k++)//依次将下标从0到G.n的顶点作为中转点
{
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
if ((A[i][k] + A[k][j]) < A[i][j])//找到更短路径长度
{
A[i][j] = A[i][k] + A[k][j];//修改路径长度
path[i][j] = path[k][j];//修改下标为j的顶点的前驱顶点
//而path[k][j]存放的是恰好是从下标为k到下标为j顶点的路径中,下标为j的顶点的前驱顶点编号
}
}
}
}
DisPath(G, A, path);
/*for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
cout << path[i][j] << " ";
}
cout << endl;
}
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
cout << A[i][j] << " ";
}
cout << endl;
}*/
}
void DisPath(MGraph G, int A[][MAXV], int path[][MAXV])
{
for (int i = 0; i < G.n; i++)
{
for (int j = 0; j < G.n; j++)
{
if (A[i][j] != 0 && A[i][j] != INF && i != j)
{
cout << "从" << G.vexs[i] << "到" << G.vexs[j] << "最短路径长度是:" << A[i][j] << endl;
int d[MAXV];
int m = 0;
d[m] = j;//先存终点的下标
int k = path[i][j];
while (k != i && k != -1)
{
m++;
d[m] = k;
k = path[i][k];
}
m++;
d[m] = i;//存起点的下标
cout << "路径是:" << d[m];
for (int p = m - 1; p >= 0; p--)
{
cout << "->" << d[p];
}
cout << endl;
}
}
}
}
//Text.cpp
#include"Floyd.h"
int main()
{
int M[][MAXV] = { {0,5,INF,7},{INF,0,4,2},{3,3,0,2},{INF,INF,1,0} };
MGraph G;
Creat(G, M, 4);
cout << "图的邻接矩阵:" << endl;
Print(G);
cout << endl;
Floyd(G);
return 0;
}