运行结果:采用迪杰斯特拉算法求单源最短路径
编写一个算法,采用迪杰斯特拉算法,输出如下图所示的有向带权图G中从顶点a到其他各顶点的最短路径长度和最短路径。图的存储结构自选。 b 4 e 15 6
源代码:
:
#include<> #include<>
#include<> exnum,&(*G).arcnum);
printf(\"请输入%d个顶点的值(<%d个字符):\\n\ for(i=0;i<(*G).vexnum;++i) /* 构造顶点向量 */ scanf(\"%s\
for(i=0;i<(*G).vexnum;++i) /* 初始化邻接矩阵 */ for(j=0;j<(*G).vexnum;++j) {
(*G).arcs[i][j].adj=INFINITY; /* 网 */ }
printf(\"请输入%d条弧的弧尾 弧头 权值(以空格作为间隔): \\n\
for(k=0;k<(*G).arcnum;++k) {
scanf(\"%s%s%d%*c\吃掉回车符 */ i=LocateVex(*G,va); j=LocateVex(*G,vb);
(*G).arcs[i][j].adj=w; /* 有向网 */ }
(*G).kind=DN; return OK; }
typedef int QElemType;
/*单链队列--队列的链式存储结构 */ typedef struct QNode {
QElemType data; struct QNode *next; }QNode,*QueuePtr; typedef struct {
QueuePtr front,rear; /* 队头、队尾指针 */ }LinkQueue; LinkQueue Q;
Status InitQueue(LinkQueue *Q) { /* 构造一个空队列Q */
(*Q).front=(*Q).rear=(QueuePtr)malloc(sizeof(QNode)); if(!(*Q).front) exit(OVERFLOW); (*Q).front->next=NULL; return OK; }
Status QueueEmpty(LinkQueue Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */ if==
return TRUE; else
return FALSE; }
Status EnQueue(LinkQueue *Q,QElemType e) { /* 插入元素e为Q的新的队尾元素 */
QueuePtr p=(QueuePtr)malloc(sizeof(QNode)); if(!p) /* 存储分配失败 */ exit(OVERFLOW); p->data=e; p->next=NULL; (*Q).rear->next=p; (*Q).rear=p; return OK; }
Status DeQueue(LinkQueue *Q,QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */ QueuePtr p;
if((*Q).front==(*Q).rear) return ERROR; p=(*Q).front->next; *e=p->data;
(*Q).front->next=p->next; if((*Q).rear==p) (*Q).rear=(*Q).front; free(p); return OK; }
void ShortestPath_DIJ(MGraph G,int v0,PathMatrix *P,ShortPathTable *D) { /* 用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度 */
/* D[v]。若P[v][w]为TRUE,则w是从v0到v当前求得最短路径上的顶点。 */ /* final[v]为TRUE当且仅当v∈S,即已经求得从v0到v的最短路径 算法 */ int v,w,i,j,min;
Status final[MAX_VERTEX_NUM]; for(v=0;v<;++v) {
final[v]=FALSE; (*D)[v]=[v0][v].adj; for(w=0;w<;++w)
(*P)[v][w]=FALSE; /* 设空路径 */
if((*D)[v](*P)[v][v0]=TRUE; (*P)[v][v]=TRUE; } }(*D)[v0]=0;
final[v0]=TRUE; /* 初始化,v0顶点属于S集 */ for(i=1;i<;++i) /* 其余个顶点 */
{ /* 开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集 */ min=INFINITY; /* 当前所知离v0顶点的最近距离 */ for(w=0;w<;++w)
if(!final[w]) /* w顶点在V-S中 */
if((*D)[w]} /* w顶点离v0顶点更近 */final[v]=TRUE; /* 离v0顶点最近的v加入S集 */ EnQueue(&Q,v);
for(w=0;w<;++w) /* 更新当前最短路径及距离 */ {
if(!final[w]&&min{ /* 修改D[w]和P[w],w∈V-S */ (*D)[w]=min+[v][w].adj;for(j=0;j<;++j)
(*P)[w][j]=(*P)[v][j]; (*P)[w][w]=TRUE; } } } }
void main() {
InitQueue(&Q);
int i,j,e,v0=0; /* v0为源点 */ MGraph g; PathMatrix p; ShortPathTable d; CreateDN(&g);
ShortestPath_DIJ(g,v0,&p,&d);
printf(\"最短路径数组p[i][j]如下:\\n\"); for(i=0;i<;++i) {
for(j=0;j<;++j)
printf(\"%2d\ printf(\"\\n\"); }
printf(\"%s到各顶点的最短路径长度为:\\n\ for(i=1;i<;++i)
printf(\"%s-%s:%d\\n\
int t[6];//用来存放最短路径的终点的序号(来自队列Q) for(i=0;i<6;i++) DeQueue(&Q,&t[i]);
printf(\"%s到各顶点的最短路径为:\\n\ for(i=1;i<;++i) {
cout<<[0]<<\"-\"<<[i]<<\"的最短路径为:\"<<[0]<<' '; for(j=1;j<;j++)
if(p[i][t[j-1]]) {
cout<<[t[j-1]]<<' ';
}
cout<运行结果:【小结或讨论】
(1) 通过本次实验,掌握了最小生成树以及最短路径的相关概念,并且会实现Prim
算法、Kruskal算法以及Dijkstra算法。
(2) 在实现Prim算法时需附设一个辅助数组closedge,以记录从U到V-U具有最
小代价的边。
(3) 在实现Kruskal算法时为所有顶点附设一个数组Vset,标记各顶点所处的连通
分量,还附设了一个结构体变量存放各边的起点、终点和边的权值;在对各边按权值大小进行排序时,采用的是堆排序,初始建的是大顶堆,最终排完序后就是按边权值从小到大的有序序列。排序过程中注意双亲结点和左右孩子结点的序号问题,因为序号是从0开始的,所以结点i的孩子结点是2*i+1。 (4) 在实现Dijkstra算法时附设了二维数组P记录从V0到各顶点的最短路径上包
含的顶点,用数组D记录各最短路径的长度,此外还附设了一个队列Q,将每次找到的最短路径的终点入队,最后输出最短路径时根据当时入队的顺序依次输出,这里队列可以用一维数组代替,用队列可以更好地体现算法的思想。 (5) 从时间复杂度上看,Prim算法的时间复杂度为O(n^2),与边数无关,适用于
求边稠密的网的最小生成树;Kruskal算法的时间复杂度为O(eloge)(e为网中边的数目),适用于边稀疏的网的最小生成树。Dijkstra算法的时间复杂度为O(n^2)。