单源最短路径
- 格式:doc
- 大小:430.00 KB
- 文档页数:12
实验四:单源最短路径一.问题描述给定带权图G和源点V,对图进行遍历并求从V到G中其余各顶点的最短路径。
二.输入及结果输入:带全图G的各个顶点及各边的权值。
输出:Dijkstra算法的结果(用矩阵表示),并给出各最短路径长度。
三.需求分析1图的深度优先搜索①数组visited[i]用来表示顶点V[i]是否被访问过。
②递归调用函数2图的广度优先搜索①队列操作的相关函数②数组visited[i]用来表示顶点V[i]是否被访问过。
3单源最短路径①需要一个辅助变量D,它的每个分量D[i]表示当前所找到的从始点V到每个终点V[i]的最短路径长度。
它的初态为:若从V到V[i]有弧,则D[i]为弧上的权值;否则置D[i]为INFINITY。
②需要二元数组P[v][w],值为1,则W是V0到V当前球的最短路径上的顶点。
③需要Final[v],值为1当且仅当已经求得V0到V的最短路径。
④用带权的邻接矩阵来表示带权有向图,arcs[i][j]表示弧<vi,vj>上的权值。
⑤函数Locate来确定顶点对应的数组编号。
四.算法描述1图的深度优先搜索深度优先搜索可以从图中的某个顶点V出发,访问此顶点,然后依次从V的未被访问过的邻接点出发深度优先遍历图,直至所有和V有路径相通的顶点都被访问,若此时还有未被访问过的节点,则重复上述过程,开始深度搜索。
2图的广度优先搜索从图中某顶点V出发,在访问了V之后一次访问V的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问他们的邻接点,并使“先被访问的顶点的邻接点先于后被访问的顶点的邻接点被访问”,直至图中所有被已访问的顶点的邻接点都被访问到。
若此时图中尚有顶点未被访问,则另选图中未被访问的结点作为起始点,重复上述过程,直至图中所有顶点都被访问。
其中要用到队列的有关算法。
3单源最短路径①记S为已经找到的从源点出发的最短路径的点的集合,它的初始状态为空集。
那么,从V出发到图上其余各顶点V[i]可能达到的最短路径的初始值为D[i]=arcs[Locate Vex(G,V)][i].②选择Vj使得:D[j]=Min{D[i] :vi S} ,Vj就是当前求得的一条从V出发的最短路径的终点。
将V[j]加入到S中。
③修改从V出发到集合V—S上任意顶点V[k]可达到的最短路径长度。
如果:D[j]+arcs[j][k]<D[k],则修改D[k]为D[k]=D[j]+arcs[j][k];④重复操作(2)(3)N-1次。
由此求得从源点V到图上其余各顶点的最短路径是以路径长度递增的序列。
五.关键模块设计1深度优先搜索void dfs(MGraph *G,int i){int j;visited[i]=1;//标记VI,表示其已被访问printf("%5s",(*G).vexs[i]);for(j=0;j<(*G).vexnum;++j) //依次搜索VI的每个邻接点if((*G).arcs[i][j].adj!=INFINITY &&!visited[j])dfs(G,j);//递归调用}2.广度优先搜索void bfs(MGraph *G,int i){int j,k;VertexType x;SqQueue Q;Initqueue_sq(&Q,(*G).vexnum);visited1[i]=1;printf("\n%5s",(*G).vexs[i]);Enqueue_sq(&Q,(*G).vexs[i]); //已访问过的初始点入队while(!Queueempty(Q)){Dequeue_sq(&Q,x);k=LocateVex(*G,x);for(j=0;j<(*G).vexnum;++j){ //依次搜索Vi的每个可能的邻接点if(j!=k&&(*G).arcs[k][j].adj!=INFINITY &&!visited1[j]){visited1[j]=1;printf("%5s",(*G).vexs[j]);Enqueue_sq(&Q,(*G).vexs[j]);//顶点入队}}}}3单源最短路径//用Dijkstra算法求有向网G的v0顶点到其余顶点v的最短路径P[v]及带权长度//D[v]。
若P[v][w]为1,则w是从v0到v当前求得最短路径上的顶点。
//final[v]为1当且仅当v∈S,即已经求得从v0到v的最短路径void ShortestPath_DIJ(MGraph G,int v0,PathMatrix *P,ShortPathTable *D){int v,w,i,j,min,v1,w1;int final[MAX_VERTEX_NUM];for(v=0;v<G.vexnum;++v){final[v]=0;(*D)[v]=G.arcs[v0][v].adj;for(w=0;w<G.vexnum;++w)(*P)[v][w]=0; //设空路径if((*D)[v]<INFINITY){(*P)[v][v0]=1;(*P)[v][v]=1;}}printf("\nfinal[]:"); //打印初始状态for(v1=0;v1<G.vexnum;++v1)printf("%6d",final[v1]);printf("\n\nD[]:");for(v1=0;v1<G.vexnum;++v1)printf("%8d",(*D)[v1]);printf("\n\nP[][]:\n");for(v1=0;v1<G.vexnum;++v1){for(w1=0;w1<G.vexnum;++w1)printf("%6d",(*P)[v1][w1]);putchar('\n');}(*D)[v0]=0;final[v0]=1; //初始化,v0顶点属于S集for(i=1;i<G.vexnum;++i) //其余G.vexnum-1个顶点{ //开始主循环,每次求得v0到某个v顶点的最短路径,并加v到S集min=INFINITY; // 当前所知离v0顶点的最近距离for(w=0;w<G.vexnum;++w)if(!final[w]) //w顶点在V-S中if((*D)[w]<min){v=w;min=(*D)[w];} //w顶点离v0顶点更近final[v]=1; //离v0顶点最近的v加入S集printf("\nfinal[]:"); //打印中间结果,跟踪数据变化for(v1=0;v1<G.vexnum;++v1)printf("%6d",final[v1]);printf("\n\nD[]:");for(v1=0;v1<G.vexnum;++v1)printf("%6d",(*D)[v1]);printf("\n\nP[][]:\n");for(v1=0;v1<G.vexnum;++v1){for(w1=0;w1<G.vexnum;++w1)printf("%6d",(*P)[v1][w1]);putchar('\n');}for(w=0;w<G.vexnum;++w) //更新当前最短路径及距离if(!final[w]&&min<INFINITY && G.arcs[v][w].adj < INFINITY&& (min+G.arcs[v][w].adj<(*D)[w])){//修改D[w]和P[w],w∈V-S(*D)[w]=min+G.arcs[v][w].adj;for(j=0;j<G.vexnum;++j)(*P)[w][j]=(*P)[v][j];(*P)[w][w]=1;}}}六.调试运行及结果输入以下图:运行结果如下七.心得与体会在调试程序过程中,开始时老是广度优先搜索出错。
后来发现是队列的入队出了错,因为在程序中同时有了图和队列的数据结构,且他们都含有顶点这一项,导致在入队是直接将Q.elem[i]入队,实际上应为G.vexs[i]入队,平时的惯性思维导致了错误。
另外,起初想用链表进行搜索,后来发现结果不对,因为图是有向的,在链表的头结点和表结点连接时会有先后顺序之分,以致搜索结果会随输入的顺序改变而改变。
所以最后该为用矩阵进行搜索,并求最短路径。
附:源程序#include <stdio.h>#include <string.h>#include <malloc.h>#define MAX_NAME 10 //顶点字符串的最大长度+1#define MAX_INFO 20 //相关信息字符串的最大长度+1#define INFINITY 10000 //用10000代替∞#define MAX_VERTEX_NUM 20 //最大顶点个数#define QUEUE_INIT_SIZE 20 //队列长度typedef int VRType ; //顶点关系的数据类型typedef char VertexType[MAX_NAME]; //顶点数据类型及长度//邻接矩阵的数据结构typedef struct{VRType adj; //为权值类型,省去弧的其他相关信息}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//图的数据结构typedef struct{VertexType vexs[MAX_VERTEX_NUM];// 顶点向量AdjMatrix arcs; //邻接矩阵int vexnum, //图的当前顶点数arcnum; //图的当前弧数} MGraph;//队列的数据结构typedef struct SqQueue{VertexType elem[MAX_VERTEX_NUM];int queuesize;int front,rear;}SqQueue;typedef int PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//路径矩阵typedef int ShortPathTable[MAX_VERTEX_NUM];//路径上的结点权int visited[MAX_VERTEX_NUM]={0},visited1[MAX_VERTEX_NUM]={0};//定位,若G中存在顶点u,则返回该顶点在图中位置;否则返回-1。