单源结点最短路径.docx
《单源结点最短路径.docx》由会员分享,可在线阅读,更多相关《单源结点最短路径.docx(17页珍藏版)》请在冰豆网上搜索。
单源结点最短路径
单源结点最短路径
一、题目
单源结点最短路径问题。
二、问题描述
求从有向图的某一结点出发到其余各结点的最短路径。
三、基本要求
(1)有向图采用邻接矩阵表示。
(2)单源结点的最短路径问题采用狄克斯特拉算法。
(3)输出有向图中从源结点到其余各结点的最短路径和最短路径值。
四、测试数据
测试数据为如下图所示的有向带权图,以结点v1作为源结点,求从结点v1到其余各结点的最短路径和最短路径的长度值。
图有向带权图
五、算法思想
1.算法流程图
算法流程图
(2)算法分析
按已给有向图构造出图G结构体,顺序表存储顶点信息,矩阵存储邻接矩阵信息,记录边的条数;选择v1为起始顶点,用狄克斯特拉算法求v1顶点到其他各个顶点的最短路径值和最短距离。
将所有的顶点分为S、T两类,S用来存放已知最短路径的顶点。
而T存放未知最短路径的顶点。
如果起始点(v1)到某个相邻顶点的最短距离已经求出,比如v1-v2的距离。
那么就把v2归入S,其余的不能直接算出最短距离的则要归入T。
刚开始的S只有起始点一个,随着算法的继续,首先将起始点相邻的点归入到S,知道最后一个顶点归入S。
六、模块划分
1.创建图
(1)算法流程
创建图流程
(2)求得G图结构如下图所示:
顺序表
V1
V2
V3
V4
V5
V6
邻接矩阵
边的条数:
11
2.求最短路径和最短距离
算法流程图
(1)求得最短距离矩阵如下
(2)求得最短距离矩阵如下
七、数据结构
1.结构体定义
(1)图的结构体定义
typedefstruct
{
SeqListVertices;//存放顶点的顺序表
intedge[MaxVertices][MaxVertices];//存放边的邻接矩阵
intnumOfEdges;//边的条数
}AdjMGraph;//图的结构体定义
(2)边信息结构体定义
typedefstruct
{
introw;//行下标
intcol;//列下标
intweight;//权值
}RowColWeight;//边信息结构体定义
八、源程序
1.子函数AdjMGraph.h
/**邻接矩阵存储存储结构下图操作的实现**/
#ifndefADJMGRAPH_H_INCLUDED
#defineADJMGRAPH_H_INCLUDED
#include"SeqList.h"//包含顺序表头文件
typedefstruct
{
SeqListVertices;//存放顶点的顺序表
intedge[MaxVertices][MaxVertices];//存放边的邻接矩阵
intnumOfEdges;//边的条数
}AdjMGraph;//图的结构体定义
/**初始化有n个顶点的顶点顺序表和邻接矩阵**/
voidInitiate(AdjMGraph*G,intn)
{
inti,j;
for(i=0;ifor(j=0;j{
if(i==j)G->edge[i][j]=0;
elseG->edge[i][j]=MaxWeight;//MaxWeight表示无穷大
}
G->numOfEdges=0;//边的条数置为0
ListInitiate(&G->Vertices);//顺序表初始化
}
/**在图中增加一个顶点**/
voidInsertVertex(AdjMGraph*G,DataTypevertex)
//在图中插入顶点vertex
{
ListInsert(&G->Vertices,G->Vertices.size,vertex);//顺序表尾插入
}
/**在图中增加一条有向边**/
voidInsertEdge(AdjMGraph*G,intv1,intv2,intweight)
//在图G中插入边,边的权为weight
{
if(v1<0||v1>=G->Vertices.size||v2<0||v2>=G->Vertices.size)
{
printf("参数v1或v2越界出错!
\n");
return;
}
G->edge[v1][v2]=weight;
G->numOfEdges++;
}
/**在图中取消一条有向边**/
voidDeleteEdge(AdjMGraph*G,intv1,intv2)
//在图G中删除边
{
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--;
}
/**取第一个邻接顶点**/
intGetFirstVex(AdjMGraphG,intv)
//在图G中需要序号为V的顶点的第一个邻接顶点
//如果这样的邻接顶点存在,则返回该邻接顶点的序号,否则返回-1
{
intcol;
if(v<0||v>=G.Vertices.size)
{
printf("参数v1越界!
\n");
return-1;
}
for(col=0;colif(G.edge[v][col]>0&&G.edge[v][col]returncol;
return-1;
}
/**取下一个邻接顶点**/
intGetNextVex(AdjMGraphG,intv1,intv2)
//在图G中寻找V1顶点的邻接顶点V2的下一个邻接顶点
{
intcol;
if(v1<0||v1>=G.Vertices.size||v2<0||v2>=G.Vertices.size)
{
printf("参数v1或v2越界出错!
\n");
return-1;
}
for(col=v2+1;colif(G.edge[v1][col]>0&&G.edge[v1][col]returncol;
return-1;
}
#endif//ADJMGRAPH_H_INCLUDED
2.子函数AdjMGraphCreate.h
/**图的创建函数**/
#ifndefADJMGRAPHCREATE_H_INCLUDED
#defineADJMGRAPHCREATE_H_INCLUDED
typedefstruct
{
introw;//行下标
intcol;//列下标
intweight;//权值
}RowColWeight;//边信息结构体定义
voidCreatGraph(AdjMGraph*G,DataTypeV[],intn,RowColWeightE[],inte)
//在图G中出入n个顶点信息V和e条边的信息E
{
inti,k;
Initiate(G,n);//顶点顺序表初始化
for(i=0;iInsertVertex(G,V[i]);//插入顶点
for(k=0;kInsertEdge(G,E[k].row,E[k].col,E[k].weight);//插入边
}
#endif//ADJMGRAPHCREATE_H_INCLUDED
3.子函数Dijkstra.h
#ifndefDIJKSTRA_H_INCLUDED
#defineDIJKSTRA_H_INCLUDED
#defineN6
voidDijkstra(AdjMGraphG,intv1,intdistance[],intpath[][N])
//带权图G从下标v1顶点到其他顶点的最短距离distance和最短路径下标path
{
intn=G.Vertices.size;
int*s=(int*)malloc(sizeof(int)*n);
intminDis,i,j,u,k;
//初始化
for(i=0;i{
path[i][0]=v1;
for(j=1;jpath[i][j]=-1;
}
for(i=0;i{
distance[i]=G.edge[v1][i];
s[i]=0;
if(i!
=v1&&distance[i]path[i][1]=i;
}
//标记顶点v0已从集合T加入到集合S中
s[v1]=1;
//在当前还未找到最短路径的顶点集中选取具有最短距离的顶点u
for(i=1;i{
minDis=MaxWeight;
for(j=0;jif(s[j]==0&&distance[j]{
u=j;
minDis=distance[j];
}
//当已不存在路径时,算法结束。
此句对非连通图是必需的
if(minDis==MaxWeight)return;
//标记顶点u已从集合T加入到集合S中
s[u]=1;
//修改从v0到其他顶点的最短路径和最短距离
for(j=0;j{
if(s[j]==0&&G.edge[u][j]{
//顶点v0经顶点U到其他顶点的最短距离和最短路径
distance[j]=distance[u]+G.edge[u][j];
for(k=0;path[u][k]!
=-1;k++)
{
path[j][k]=path[u][k];
}
path[j][k++]=j;
path[j][k]=-1;
}
}
}
}
#endif//DIJKSTRA_H_INCLUDED
4.子函数SeqList.h
#ifndefSeqList_H
#defineSeqList_H
typedefstruct
{
DataTypelist[MaxSize];//DataType这个在你用的时候可以去定义它的类型
intsize;//指这个表的总长度
}SeqList;//定义抽象数据类型SeqList
voidListInitiate(SeqList*L)//初始化顺序表L
{
L->size=0;//定义初始元素个数
}
intListLength(SeqListL)
{
returnL.size;
}
intListInsert(SeqList*L,inti,DataTypex)
//在顺序表L的位置i(0<=i<=size为当前数据元素个数)插入数据元素值x
//插入成功返回1,否则返回0
{
intj;
if(L->size>=MaxSize)
{
printf("表已满无法插入!
\n");
return0;
}
elseif(i<0||i>L->size)
{
printf("参数i不合法!
\n");
return0;
}
else
{
for(j=L->size;j>i;j--)
{
L->list[j]=L->list[j-1];
}
L->list[i]=x;
L->size++;
return1;
}
}
intListDelete(SeqList*L,inti,DataType*x)
//删除顺序表L中位置i上的数据元素并保存到x中
//插入成功返回1,否则返回0
{
intj;
if(L->size<=0)
{
printf("表已空无法插入!
\n");
return0;
}
elseif(i<=0||i>L->size-1)
{
printf("参数i不合法!
\n");
return0;
}
else
{
*x=L->list[i];
for(j=i+1;j<=L->size-1;j++)
L->list[j-1]=L->list[j];
L->size--;
return1;
}
}
intListGet(SeqListL,inti,DataType*x)
//取顺序表L中第i个元素的值,取到则返回1,否则返回0
{
if(i<0||i>L.size-1)
{
printf("参数i不合法!
\n");
return0;
}
else
{
*x=L.list[i];
return1;
}
}
intListNotEmpty(SeqListL)
//判断该表是否为空
//如果表的总长度小于等于0,则说明该表为空,返回1
{
if(L.size<=0)
return0;
else
return1;
}
#endif
5.主函数
#include
#include
#include
typedefcharDataType;
#defineMaxSize10//定义顺序表数组的最大值
#defineMaxVertices30//定义顶点的最大值
#defineMaxWeight10000//定义无穷大的具体值
#include"AdjMGraph.h"
#include"AdjMGraphCreate.h"
#include"Dijkstra.h"
intmain()
{
AdjMGraphg;
chara[]={'1','2','3','4','5','6'};
RowColWeightrcw[]={{0,1,10},{0,2,12},{1,3,16},{1,4,25},{2,0,4},{2,1,3},
{2,3,12},{2,5,8},{3,4,7},{5,3,2},{5,4,10}};
inti,n=6,e=11,j;
intdistance[6],path[6][6];
CreatGraph(&g,a,n,rcw,e);
Dijkstra(g,0,distance,path);
printf("从顶点v%c到其他各顶点的最短距离为:
\n",g.Vertices.list[0]);
for(i=0;iprintf("到顶点v%c的最短距离为%d\n",g.Vertices.list[i],distance[i]);
printf("\n从顶点v%c到其他各顶点最短路径为:
\n",g.Vertices.list[0]);
for(i=0;i{
printf("\n到顶点v%c的最短路径为:
",g.Vertices.list[i]);
for(j=0;jif(path[i][j]!
=-1)
printf("v%c",g.Vertices.list[path[i][j]]);
}
return0;
}
九、测试情况
程序运行结果