1. 邻接矩阵实现
需要注意的一点是在定义最短路径数组
ShortestPathTable
和邻接矩阵arcs
及变量min_
时要定义为long long int
而不是int
,因为在初始化邻接矩阵时我们将inf
定义为int
型数据最大值0x7fffffff
,那么在D[j]
的松弛操作中可能涉及某个值加inf
,这样就会产生数值溢出,最后导致求出错误的最短路径D[j]
。
C++代码
/*单源最短路径——邻接矩阵实现*/
#define MAX_VERTEX_NUM 100
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
const int INF = 0x7fffffff;
typedef int VertexType; //顶点类型
typedef long long int ShortestPathTable[MAX_VERTEX_NUM]; //最短路径表
typedef long long int AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //邻接矩阵
typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; //路径数组
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; //顶点表
AdjMatrix arcs; //邻接矩阵
int vexnum; //顶点数
int arcnum; //边数
int GraphKind;//图的种类
}MGraph;//图
/*定位顶点*/
int LocateVertex(MGraph& G, VertexType v)
{
int i;
for (i = 0; i < G.vexnum; i++)
if (v == G.vexs[i])
return i;
return -1;
}
/*创建无向网*/
void CreateGraph(MGraph& G)
{
cout << "请输入顶点数:";
cin >> G.vexnum;
cout << "请输入边数:";
cin >> G.arcnum;
//初始化顶点值
for (int i = 0; i < G.vexnum; i++)
G.vexs[i] = i + 1;
//初始化邻接矩阵都为无穷大
for (int i = 0; i < G.vexnum; i++)
for (int j = 0; j < G.vexnum; j++)
G.arcs[i][j] = INF;
cout << "请输入与边关联的顶点和权值信息:" << endl;
//输入顶点及权值信息
for (int k = 0; k < G.arcnum; k++)
{
VertexType v1, v2;
int w;
cin >> v1 >> v2 >> w;
int i = LocateVertex(G, v1);
int j = LocateVertex(G, v2);
G.arcs[i][j] = w;
//G.arcs[j][i] = w;
}
}
/*Dijkstra算法求解最短路径
1. 初始化最短路径数组D[]为初始顶点v0到其余各点的距离
2. 将初始顶点加入集合S
3. 循环(顶点数 - 1)次 源点v0除外
1. 求出D[]中最小值
2. 将最小值对应的终点加入集合S
3. 更新D[]数组,进行松弛操作(因为S集合变了 那么源点v0到集合V-S中顶点的距离可能变短)
*/
void ShortestPath_DIJ(MGraph& G, ShortestPathTable& D, PathMatrix& P, VertexType v0)
{
int k = LocateVertex(G, v0);
int final[MAX_VERTEX_NUM] = { 0 };//辅助数组 final[v]=1当且仅当v∈S,即已经求得v0到v的最短路径
final[k] = 1;// v0 加入集合S
for (int i = 0; i < G.vexnum; i++)
{
D[i] = G.arcs[k][i];
for (int j = 0; j < G.vexnum; j++)//初始化路径数组 为空0 P[i][j]为1 则j是v0->i当前求得最短路径上的顶点
{
P[i][j] = 0;
}
if (D[i] < INF) //v0和i之间连通
{
P[i][k] = 1;//v0肯定是v0->i上的点
P[i][i] = 1;//i肯定是v0->i上的点
}
}
D[k] = 0; //v0 到 v0 距离为0
for (int i = 1; i < G.vexnum; i++)//需要循环(顶点数-1)次即可
{
int min_ = INF;
int flag = 0;//标记最小值的下标
for (int j = 0; j < G.vexnum; j++) //1. 求出D[]中的最小值
{
if (!final[j] && D[j] < min_)//要跳过v0顶点
{
min_ = D[j];
flag = j;
}
}
final[flag] = 1;//2. 将顶点flag加入S
//3. 对D[]进行松弛操作
for (int j = 0; j < G.vexnum; j++)
{
//!final[j] 属于V-S final[j]属于S 在S中寻找D[flag] + (flag,j) 使得 D[j] 更小
//if(!final[j] && D[flag] + G.arcs[flag][j] < D[j])
if (!final[j] && min_ + G.arcs[flag][j] < D[j])
{
D[j] = min_ + G.arcs[flag][j];
memcpy(P[j], P[flag], sizeof(P[j]));//将flag顶点的路径数组 赋给 j顶点的路径数组
P[j][j] = 1;//j顶点在v0->j的当前最短路径上
}
}
}
}
int main()
{
ShortestPathTable D;
MGraph G;
PathMatrix P;
CreateGraph(G);
cout << "请输入起始顶点:";
VertexType v0;
cin >> v0;
ShortestPath_DIJ(G, D, P, v0);
for (int i = 0; i < G.vexnum; i++)
{
cout << v0 << "-->" << G.vexs[i] << ":";
if(D[i] == INF)
cout<<"inf";
else
cout <<D[i];
cout << "; 最短路径经过的顶点:";
for (int j = 0; j < G.vexnum; j++)
{
if (P[i][j] == 1)
{
cout << G.vexs[j] << " ";
}
}
cout << endl;
}
system("pause");
return 0;
}
/*
4 6
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
6 8
1 3 10
1 5 30
1 6 100
2 3 5
3 4 50
4 6 10
5 4 20
5 6 60
*/
输出结果
请输入顶点数:6
请输入边数:8
请输入与边关联的顶点和权值信息:
1 3 10
1 5 30
1 6 100
2 3 5
3 4 50
4 6 10
5 4 20
5 6 60
请输入起始顶点:2
2–>1:inf; 最短路径经过的顶点:
2–>2:0; 最短路径经过的顶点:
2–>3:5; 最短路径经过的顶点:2 3
2–>4:55; 最短路径经过的顶点:2 3 4
2–>5:inf; 最短路径经过的顶点:
2–>6:65; 最短路径经过的顶点:2 3 4 6
2. 邻接链表实现
此处和邻接矩阵实现方法一样,需要将
info
类型和ShortestPathTable
设置为long long
,同时代码中的变量min_
也要设置为long long
。
C++代码
#include<iostream>
using namespace std;
typedef int VertexType;
#define MAX_VERTEX_NUM 100
#define INF 0x7fffffff
typedef struct ArcNode
{
int adjvex;//弧指向的顶点的位置
ArcNode* nextarc;//指向下一个与该顶点邻接的顶点
long long info;//弧的相关信息
}ArcNode;//边表结点
typedef struct VNode
{
VertexType data;//用于存储顶点
ArcNode* firstarc;//指向第一个与该顶点邻接的顶点
}VNode, AdjList[MAX_VERTEX_NUM];//表头节点,顺序表存储
typedef struct
{
AdjList vertices;//邻接表
int vexnum, arcnum;//边数,顶点数
int kind;//图的种类
}ALGraph;
typedef long long int ShortPathTable[MAX_VERTEX_NUM]; //最短路径长度
int LocateVertex(ALGraph& G, VertexType& v)
{
int i;
for (i = 0; i < G.vexnum; i++)
if (G.vertices[i].data == v)
return i;
return -1;
}
void CreateGraph(ALGraph& G)
{
cout << "请输入顶点数:";
cin >> G.vexnum;
cout << "请输入边数:";
cin >> G.arcnum;
for (int i = 0; i < G.vexnum; i++)
{
G.vertices[i].data = i + 1;
G.vertices[i].firstarc = NULL;
}
cout << "请输入与边关联的顶点和权值信息:" << endl;
for (int k = 0; k < G.arcnum; k++)//无向图
{
VertexType v1, v2;
int w;
cin >> v1 >> v2 >> w;
int i = LocateVertex(G, v1);
int j = LocateVertex(G, v2);
ArcNode* p;
/*j为入i为出创建邻接链表*/
p = new ArcNode;
p->adjvex = j;
p->info = w;
p->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p;
/*i为入j为出创建邻接链表*/
// p = new ArcNode;
// p->adjvex = i;
// p->info = w;
// p->nextarc = G.vertices[j].firstarc;
// G.vertices[j].firstarc = p;
}
}
void ShortestPath_DIJ(ALGraph& G, ShortPathTable& D, VertexType v0)
{
//用Dijkstra算法求有向网v0到其余各顶点带权长度D[v];
//final[v]=true当且仅当v∈S,即已经求得v0到v的最短路径
int final[MAX_VERTEX_NUM] = { 0 };
for(int i = 0; i < G.vexnum; i++)
D[i] = INF;
int k = LocateVertex(G, v0);
ArcNode* p = G.vertices[k].firstarc;
while (p)
{
int w = p->adjvex;
D[w] = p->info;
p = p->nextarc;
}
D[k] = 0;
final[k] = 1;//初始化,v0顶点属于S;
for (int i = 1; i < G.vexnum; i++)
{
long long int min_ = INF;
int v = 0;
for (int j = 0; j < G.vexnum; j++)
{
if (!final[j] && D[j] < min_)
{
v = j;
min_ = D[j];
}
}
final[v] = 1;
//更新当前最短距离D[];
p = G.vertices[v].firstarc;
while (p)
{
int w = p->adjvex;
if (!final[w] && min_ + p->info < D[w])
D[w] = min_ + p->info;
p = p->nextarc;
}
}
}
int main()
{
ALGraph G;
ShortPathTable D;
int v0;
CreateGraph(G);
cout << "请输入起始顶点:";
cin >> v0;
ShortestPath_DIJ(G, D, v0);
for (int i = 0; i < G.vexnum; i++)
{
cout << v0 << "-->" << G.vertices[i].data << ":";
if (D[i] == INF)
cout << "inf";
else
cout << D[i];
cout << endl;
}
cout << endl;
return 0;
}
输出结果
请输入顶点数:6
请输入边数:8
请输入与边关联的顶点和权值信息:
1 3 10
1 5 30
1 6 100
2 3 5
3 4 50
4 6 10
5 4 20
5 6 60
请输入起始顶点:2
2–>1:inf
2–>2:0
2–>3:5
2–>4:55
2–>5:inf
2–>6:65