迪杰斯特拉算法
问题描述
\quad 对于给定的有向带权图,从一个确定的顶点计算到其余各顶点的最短路径问题。
算法思想
\quad 设置两个顶点集合 S S S和 T T T,集合 S S S中存放已经找到的最短路径的顶点,集合 T T T中存放当前还未找到的路径的顶点。初始状态时,集合 S S S中只包含源点,设为 v 0 {v_0} v0,然后从集合 T T T中选择找到源点 v 0 {v_0} v0路径长度最短的顶点 u u u加入到集合 S S S中,集合 S S S中每加入一个新的顶点 u {u} u,都要修改源点 v 0 {v_0} v0到集合T中剩余的顶点的当前的最短路径长度值,集合 T T T中各顶点新的当前最短路径长度值为原来的当前最短路径长度值与源点过顶点 到达该顶点的路径长度的较小者。此过程不断重复,直到集合 T T T中所有的顶点全部加入到集合 S S S中为止。
函数模块
(
1
)
(1)
(1) 该程序主要包含四个头文件,分别为
A
d
j
M
G
r
a
p
h
.
h
,
A
d
j
M
G
r
a
p
h
C
r
e
a
t
.
h
,
D
i
j
s
t
r
a
.
h
,
S
e
q
L
i
s
t
.
h
。
AdjMGraph.h,AdjMGraphCreat.h,Dijstra.h,SeqList.h。
AdjMGraph.h,AdjMGraphCreat.h,Dijstra.h,SeqList.h。
(
2
)
D
i
j
s
t
r
a
.
h
(2) Dijstra.h
(2)Dijstra.h中存放
D
i
j
s
t
r
a
(
A
d
j
M
G
r
a
p
h
G
,
i
n
t
v
0
,
i
n
t
d
i
s
t
a
n
c
e
[
]
,
i
n
t
p
a
t
h
[
]
)
Dijstra(AdjMGraph G,int v0,int distance[ ],int path[])
Dijstra(AdjMGraphG,intv0,intdistance[],intpath[])。该函数共有四个参数,两个输入参数,分别为带权图
G
G
G,源点序号
v
0
{v_0}
v0;连个输出参数分别为
d
i
s
t
a
n
c
e
[
]
distance[]
distance[]和
p
a
t
h
[
]
path[]
path[]。
数据结构
图
t
y
p
e
d
e
f
s
t
r
u
c
t
typedef struct
typedefstruct
{
S
e
q
L
i
s
t
V
e
r
t
i
c
e
s
;
/
/
存
放
顶
点
的
顺
序
表
SeqList Vertices;//存放顶点的顺序表
SeqListVertices;//存放顶点的顺序表
i
n
t
e
d
g
e
[
M
a
x
V
e
r
t
i
c
e
s
]
[
M
a
x
V
e
r
t
i
c
e
s
]
;
/
/
存
放
边
的
邻
接
矩
阵
int edge[MaxVertices][MaxVertices];//存放边的邻接矩阵
intedge[MaxVertices][MaxVertices];//存放边的邻接矩阵
i
n
t
n
u
m
O
f
E
d
g
e
s
;
/
/
边
的
条
数
int numOfEdges;//边的条数
intnumOfEdges;//边的条数
}
A
d
j
M
G
r
a
p
h
;
AdjMGraph;
AdjMGraph;
带权图
t
y
p
e
d
e
f
s
t
r
u
c
t
typedef struct
typedefstruct
{
i
n
t
r
o
w
;
/
/
行
int row;//行
introw;//行
i
n
t
c
o
l
;
/
/
列
int col;//列
intcol;//列
i
n
t
w
e
i
g
h
t
;
/
/
权
值
int weight;//权值
intweight;//权值
}
R
o
w
C
o
l
W
e
i
g
h
t
;
RowColWeight;
RowColWeight;
测试数据
(
1
)
(1)
(1)顶点集合
A
,
B
,
C
,
D
,
E
,
F
{A,B,C,D,E,F}
A,B,C,D,E,F
(
2
)
(2)
(2)边的集合{{
0
,
2
,
5
0,2,5
0,2,5},{
0
,
3
,
25
0,3,25
0,3,25},{
1
,
0
,
4
1,0,4
1,0,4},{
1
,
4
,
6
1,4,6
1,4,6},{
2
,
1
,
15
2,1,15
2,1,15},{
2
,
5
,
9
2,5,9
2,5,9},{
4
,
3
,
8
4,3,8
4,3,8},{
5
,
3
,
12
5,3,12
5,3,12},{
5
,
4
,
20
5,4,20
5,4,20}}
C语言程序
头文件
A d j M G r a p h . h AdjMGraph.h AdjMGraph.h
#ifndef ADJMGRAPH_H_INCLUDED
#define ADJMGRAPH_H_INCLUDED
#endif // ADJMGRAPH_H_INCLUDED
#include"SeqList.h"
typedef struct
{
SeqList Vertices;//存放顶点的顺序表
int edge[MaxVertices][MaxVertices];//存放边的邻接矩阵
int numOfEdges;//边的条数
}AdjMGraph;
void Initiate(AdjMGraph *G,int n)//n是顶点个数
{
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(i==j)
G->edge[i][j]=0;//不存在自环
else
G->edge[i][j]=MaxWeight;//边的权值为无穷大,即不存在边
}
G->numOfEdges=0;//初始时边的数量为0
ListInitiate(&G->Vertices);
}
void InsertVertex(AdjMGraph *G,DataType vertex)
{
ListInsert(&G->Vertices,G->Vertices.size,vertex);//在顺序表尾部插入
//顺序表,插入位置,数据元素
}
void InsertEdge(AdjMGraph *G,int v1,int v2,int weight)
//在图G插入边<v1,v2>,权值为weight
{
if(v1<0||v1>=G->Vertices.size||v2<0||v2>=G->Vertices.size)
{
printf("插入时,参数v1或v2不合法\n");
return;//函数结束标志
}
if(0<G->edge[v1][v2] && G->edge[v1][v2]<weight)//边已存在,不能覆盖
{
printf("边已存在\n");
return;//函数结束标志
}
G->edge[v1][v2]=weight;
G->numOfEdges++;
}
void DeleteEdge(AdjMGraph *G,int v1,int v2)
{
if(v1<0||v1>=G->Vertices.size||v2<0||v2>=G->Vertices.size||v1==v2)
{
printf("删除时,参数v1或v2不合法\n");
return;//函数结束标志
}
if(G->edge[v1][v2]==MaxWeight||v1==v2)
{
printf("该边不存在,无法删除!\n");
return;
}
G->edge[v1][v2]=MaxWeight;
G->numOfEdges--;
}
int GetFirstVex(AdjMGraph G,int v)
//在图G中寻找序号v的顶点的第一个邻接顶点
{
int col;
if(v<0||v>=G.Vertices.size)
{
printf("参数出界,获取失败!\n");
return -1;
}
for(col=0;col<G.Vertices.size;col++)
if(G.edge[v][col]>0 && G.edge[v][col]<MaxWeight)
return col;
return -1;//未找到
}
int GetNextVex(AdjMGraph G,int v1,int v2)
//在图中找v1顶点的邻接顶点v2的下一个顶点
{
int col;
if(v1<0||v1>=G.Vertices.size||v2<0||v2>=G.Vertices.size)
{
printf("参数v1或v2越界,获取失败!\n");
return -1;//函数结束标志
}
for(col=v2+1;col<G.Vertices.size;col++)
if(G.edge[v1][col]>0 && G.edge[v1][col]<MaxWeight)
return col;
return -1;//未找到
}
A d j M G r a p h C r e a t . h AdjMGraphCreat.h AdjMGraphCreat.h
#ifndef ADJMGRAPHCREAT_H_INCLUDED
#define ADJMGRAPHCREAT_H_INCLUDED
#endif // ADJMGRAPHCREAT_H_INCLUDED
typedef struct
{
int row;//行
int col;//列
int weight;//权值
}RowColWeight;
void CreatGraph(AdjMGraph *G,DataType V[],int n,RowColWeight E[],int e)
//在图中插入n个顶点信息V和e条边信息E,n是顶点数,e是边数
{
int i,k;
Initiate(G,n);//顶点顺序表初始化
for(i=0;i<n;i++)//插入顶点
InsertVertex(G,V[i]);
for(k=0;k<e;k++)//插入边
InsertEdge(G,E[k].row,E[k].col,E[k].weight);
}
D i j s t r a . h Dijstra.h Dijstra.h
#ifndef DIJKSTRA_H_INCLUDED
#define DIJKSTRA_H_INCLUDED
#endif // DIJKSTRA_H_INCLUDED
void Dijkstra(AdjMGraph G, int v0, int distance[], int path[])
//带权图G从下标v0顶点到其他顶点的最短距离distance和最短路径下标path
{
int n=G.Vertices.size;//
int *s=(int *)malloc(sizeof(int )*n);
int minDis,i,j,u;
//初始化
for(i=0;i<n;i++)
{
distance[i]=G.edge[v0][i];
s[i]=0;//标记
if(i!=v0 && distance[i]<MaxWeight)
path[i]=v0;
else
path[i]=-1;
}
s[v0]=1;//标记顶点v0已从集合T加入到集合S中
//当前还未找到最短路径的顶点集合中选取具有最短路径的顶点u
for(i=1;i<n;i++)
{
minDis=MaxWeight;
for(j=0;j<n;j++)
{
if(s[j]==0 && distance[j]<minDis)
{
u=j;
minDis=distance[j];
}
}
//当已不存在路径时,算法结束。此语句对于非连通图是必须的
if (minDis==MaxWeight)return ;//结束程序
s[u]=1;//标记顶点u已从集合T加入到集合S中
//修改从v0到其他顶点的最短路径和最短距离
for(j=0;j<n;j++)
if(s[j]==0 && G.edge[u][j]<MaxWeight && distance[u]+G.edge[u][j]<distance[j])
//松弛操作
{
//顶点v0经过顶点u到其他顶点的最短距离和最短路径
distance[j]=distance[u]+G.edge[u][j];
path[j]=u;
}
}
}
S e q L i s t . h SeqList.h SeqList.h
#ifndef SEQLIST_H_INCLUDED
#define SEQLIST_H_INCLUDED
#endif // SEQLIST_H_INCLUDED
//typedef int DataType;//定义DataType为int
typedef struct//线性表定义
{
DataType List[MaxSize];//一维数组
int size;//储存线性表长度
}SeqList;//线性表的名字SeqList,即定义的结构体名称为SeqList
void ListInitiate(SeqList *L)//初始化线性表
{//初始化时,会修改size的值,因此必须用指针
L->size=0;//初试元素个数为0
}
int ListLength(SeqList L)//线性表元素个数
{//可以不用指针,因为没有修改值,只是返回值
return L.size;
}
int ListInsert(SeqList *L,int i,DataType x)
{//将DataType类型的x插入到线性表L的第i个位置
int j;
if (L->size>=MaxSize)
{
printf("操作不合法,线性表已满!\n");
return 0;
}
else if (i<0||i>L->size)
{
printf("参数不合法!\n");
return 0;
}
else
{
//从后向前依次后移数据,若有10个元素,size=10,则从List[10]开始
for (j=L->size;j>i;j--)
L->List[j]=L->List[j-1];
L->List[i]=x;
L->size++;
return 1;
}
}
int ListDelete(SeqList *L,int i,DataType *x)
{
int j;
if (L->size<=0)
{
printf("操作不合法,线性表已空!\n");
return 0;
}
else if (i>L->size-1||i<0)
{//数组从Lst[0]开始,到Lst[size-1]结束
printf("参数不合法!\n");
return 0;
}
else
{
*x=L->List[i];//保存被删除元素
for(j=i+1;j<=L->size-1;j++)
L->List[j-1]=L->List[j];
L->size--;
return 1;
}
}
int ListGet(SeqList L,int i,DataType *x)
{
if(i<0||i>L.size)
{
printf("参数不合法!\n");
return 0;
}
else
{
*x=L.List[i];
return 1;
}
}
主文件
#include <stdio.h>
#include <stdlib.h>
#include<malloc.h>
typedef char DataType;
#define MaxVertices 10
#define MaxWeight 10000
#define MaxSize 10// 顺序表的长度
#include"AdjMGraph.h"
#include"AdjMGraphCreat.h"
#include"Dijkstra.h"
#include''SeqList.h''
int main()
{
AdjMGraph g;
char a[]={'A','B','C','D','E','F'};
RowColWeight rcw[]={{0,2,5},{0,3,25},{1,0,4},{1,4,6},{2,1,15},{2,5,9},{4,3,8},{5,3,12},{5,4,20}}
int i,n=6,e=9;
int distance[6],path[6];
CreatGraph(&g,a,n,rcw,e);
Dijkstra(g,0,distance,path);
printf("从顶点%c到其他各顶点的最短距离为:\n",g.Vertices.List[0]);
for(i=0;i<n;i++)
printf("到顶点%c的最短距离为%d:\n",g.Vertices.List[i],distance[i]);
printf("从顶点%c到其他各顶点的最短路径的前一顶点为:\n",g.Vertices.List[0]);
for(i=0;i<n;i++)
if(path[i]!=-1)
printf("到顶点%c的前一顶点为%c\n",g.Vertices.List[i],g.Vertices.List[path[i]]);
return 0;
}