Dijkstra算法是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。该算法是由荷兰计算机科学家迪杰斯特拉于1959年提出的。
/**
* 实验题目:
* 采用迪杰斯特拉算法求带权有向图的最短路径
* 实验目的:
* 领会迪杰斯特拉算法求带权有向图中单源最短路径的过程和相关算法设计
* 实验内容:
* 编写程序实现求带权有向图中单源最短路径的狄克斯特拉算法。并输出如
* 图8.1所示的带权有向图G中从顶点0到其余各顶点的最短路径长度和最短路径。
*/
图8.1
#include <stdio.h>
#include <malloc.h>
#define INF 32767 //定义∞
#define MAXV 100 //最大顶点个数
typedef char InfoType;
/*-------------------------以下定义邻接矩阵类型---------------------------*/
typedef struct
{
int no; //顶点编号
InfoType info; //顶点信息
}VertexType; //顶点类型
typedef struct
{
int edges[MAXV][MAXV]; //邻接矩阵数组(用一个二维数组存放顶点间关系(边或弧)的数据)
int n; //顶点数
int e; //边数
VertexType vexs[MAXV]; //存放顶点信息(用一个一维数组存放图中所有顶点数据)
}MatGraph; //完整的图邻接矩阵类型
//邻接表表示法-将每个顶点的邻接点串成一个单链表
/*-----------以下定义邻接表类型--------------*/
typedef struct ArcNode
{
int adjvex; //该边的邻接点编号
struct ArcNode *nextarc; //指向下一条边的指针
int weight; //该边的相关信息,如权值(用整型表示)
}ArcNode; //边结点类型
typedef struct VNode
{
InfoType info; //顶点其他信息
int cnt; //存放顶点入度,仅用于拓扑排序
ArcNode *firstarc; //指向第一条边
}VNode; //邻接表结点类型
typedef struct
{
VNode adjlist[MAXV]; //邻接表头结点数组
int n; //图中顶点数
int e; //图中边数
}AdjGraph; //完整的图邻接表类型
/*-------------------------邻接矩阵的基本运算算法---------------------------*/
/*------------由边数组A、顶点数n和边数e创建图的邻接矩阵g--------------------*/
void CreateMat(MatGraph &g, int A[MAXV][MAXV], int n, int e)
{
int i, j;
g.n = n;
g.e = e;
for(i = 0; i < g.n; i++)
for(j = 0; j < g.n; j++)
g.edges[i][j] = A[i][j];
}
/*------------输出邻接矩阵g--------------------*/
void DispMat(MatGraph g)
{
int i, j;
for(i = 0; i < g.n; i++)
{
for(j = 0; j < g.n; j++)
{
if(g.edges[i][j] != INF)
printf("%4d", g.edges[i][j]);
else
printf("%4s", "∞");
}
printf("\n");
}
}
/*-------------------------邻接表的基本运算算法---------------------------*/
/*-------------------由边数组A、顶点数n和边数e创建图的邻接表G--------------------*/
void CreateAdj(AdjGraph *&G, int A[MAXV][MAXV], int n, int e)
{
int i, j;
ArcNode *p;
G = (AdjGraph *)malloc(sizeof(AdjGraph));
for(i = 0; i < n; i++) //给邻接表中所有头结点的指针域置初值NULL
{
G->adjlist[i].firstarc = NULL;
}
for(i = 0; i < n; i++) //检查邻接矩阵中的每个元素
{
for(j = n - 1; j >= 0; j--)
{
if(A[i][j] != 0 && A[i][j] != INF) //存在一条边
{
p = (ArcNode *)malloc(sizeof(ArcNode)); //创建一个结点p
p->adjvex = j; //邻接点编号
p->weight = A[i][j]; //边的权重
p->nextarc = G->adjlist[i].firstarc; //采用头插法插入结点p
G->adjlist[i].firstarc = p;
}
}
}
G->n = n;
G->e = e;
}
/*-------------------输出邻接表G--------------------*/
void DispAdj(AdjGraph *G)
{
ArcNode *p;
for(int i = 0; i < G->n; i++)
{
p = G->adjlist[i].firstarc;
printf("顶点%d: ", i);
while(p != NULL)
{
printf("%3d[%d]->", p->adjvex, p->weight); //邻接点编号[权重]
p = p->nextarc;
}
printf("∧\n");
}
}
/*-------------------销毁图的邻接表G--------------------*/
void DestroyAdj(AdjGraph *&G)
{
ArcNode *pre, *p;
for(int i = 0; i < G->n; i++)
{
pre = G->adjlist[i].firstarc; //pre指向第i个单链表的首结点
if(pre != NULL)
{
p = pre->nextarc;
while(p != NULL) //释放第i个单链表的所有边结点
{
free(pre);
pre = p;
p = p->nextarc;
}
free(pre);
}
}
free(G); //释放头结点数组
}
/*------------------输出从顶点v出发的所有最短路径-------------------*/
static void Dispath(MatGraph g, int dist[], int path[], int S[], int v)
{
int i, j, k;
int apath[MAXV], d; //存放一条最短路径(逆向)及其顶点个数
//循环输出从顶点v到i的路径
for(i = 0; i < g.n; i++)
{
if(S[i] == 1 && i != v)
{
printf(" 从顶点%d到顶点%d的路径长度为:%d\t路径为:", v, i, dist[i]);
d = 0; apath[d] = i; //添加路径上的终点
k = path[i];
if(k == -1) //没有路径的情况
printf("无路径\n");
else //存在路径时输出该路径
{
while(k != v)
{
d++;
apath[d] = k;
k = path[k];
}
d++; apath[d] = v; //添加路径上的起点
printf("%d", apath[d]); //先输出起点
for(j = d - 1; j >= 0; j--) //再输出其余顶点
printf(", %d", apath[j]);
printf("\n");
}
}
}
}
/*------------------迪杰斯特拉算法-----------------*/
//求图g中从顶点v出发的单源最短路径长度和最短路径
static void Dijstra(MatGraph g, int v)
{
int dist[MAXV], path[MAXV];
int S[MAXV]; //S[i]=1表示顶点i在S中,S[i]=0表示顶点i在U中
int i, j, u;
int Mindis;
for(i = 0; i < g.n; i++)
{
dist[i] = g.edges[v][i]; //距离初始化
S[i] = 0; //S[i]置0
if(g.edges[v][i] < INF) //路径初始化
path[i] = v;
else
path[i] = -1;
}
//源点编号v放入S中
S[v] = 1;
path[v] = 0;
//循环直到所有顶点的最短路径都求出
for(i = 0; i < g.n - 1; i++)
{
Mindis = INF; //Mindis置最大长度初值
for(j = 0; j < g.n; j++)
{
if(S[j] == 0 && dist[j] < Mindis)
{
u = j;
Mindis = dist[j];
}
}
//顶点u加入S中
S[u] = 1;
//修改不在S中(即U中)的顶点的最短路径
for(j = 0; j < g.n; j++)
{
if(S[j] == 0)
{
if((g.edges[u][j] < INF) && (dist[u] + g.edges[u][j] < dist[j]))
{
dist[j] = dist[u] + g.edges[u][j];
path[j] = u;
}
}
}
}
//输出最短路径
Dispath(g, dist, path, S, v);
}
int main(void)
{
int v = 0;
MatGraph g;
int A[MAXV][MAXV] = {
{0, 5, INF, 7, INF, INF},
{INF, 0, 4, INF, INF, INF},
{8, INF, 0, INF, INF, 9},
{INF, INF, 5, 0, INF, 6},
{INF, INF, INF, 5, 0, INF},
{3, INF, INF, INF, 1, 0}
};
int n = 6; //图中的顶点数
int e = 10; //图中的边数
CreateMat(g, A, n, e); //建立图8.1的邻接矩阵
printf("有向图G的邻接矩阵:\n");
DispMat(g);
printf("迪杰斯特拉算法求解结果:\n");
Dijstra(g, v);
return 0;
}
测试结果:
有向图G的邻接矩阵:
0 5 ∞ 7 ∞ ∞
∞ 0 4 ∞ ∞ ∞
8 ∞ 0 ∞ ∞ 9
∞ ∞ 5 0 ∞ 6
∞ ∞ ∞ 5 0 ∞
3 ∞ ∞ ∞ 1 0
迪杰斯特拉算法求解结果:
从顶点0到顶点1的路径长度为:5 路径为:0, 1
从顶点0到顶点2的路径长度为:9 路径为:0, 1, 2
从顶点0到顶点3的路径长度为:7 路径为:0, 3
从顶点0到顶点4的路径长度为:14 路径为:0, 3, 5, 4
从顶点0到顶点5的路径长度为:13 路径为:0, 3, 5