单源结点最短路径

单源结点最短路径

一、题目

单源结点最短路径问题。

二、问题描述

求从有向图的某一结点出发到其余各结点的最短路径。

三、基本要求

(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 图结构如下图所示:

2. 求最短路径和最短距离

算法流程图

(1)求得最短距离矩阵如下

⎡0-1-1-1⎢01-1-1⎢

⎢02-1-1

path [6][6]=⎢

⎢0253⎢0253⎢

⎢025-1⎣

-1-1⎤

-1-1⎥⎥-1-1⎥

-1-1⎥4-1⎥

-1-1⎦⎥

(2)求得最短距离矩阵如下

distance [6]=[[1**********]]

七、数据结构

1. 结构体定义

(1)图的结构体定义

typedef struct {

SeqList Vertices; //存放顶点的顺序表 int edge[MaxVertices][MaxVertices]; //存放边的邻接矩阵 int numOfEdges; }AdjMGraph; (2)边信息结构体定义 typedef struct {

int row; int col;

int weight; }RowColWeight;

八、源程序

1. 子函数AdjMGraph.h

/**邻接矩阵存储存储结构下图操作的实现**/

#ifndef ADJMGRAPH_H_INCLUDED #define ADJMGRAPH_H_INCLUDED

#include "SeqList.h"

typedef struct {

SeqList Vertices; int edge[MaxVertices][MaxVertices]; int numOfEdges; }AdjMGraph;

/**初始化有n 个顶点的顶点顺序表和邻接矩阵**/

//边的条数 //图的结构体定义 //行下标 //列下标 //权值

//边信息结构体定义

//包含顺序表头文件 //存放顶点的顺序表 //存放边的邻接矩阵 //边的条数

//图的结构体定义

void Initiate(AdjMGraph *G, int n) {

int i,j;

for(i=0;i

for(j=0;j

if(i==j) G->edge[i][j]=0;

else G->edge[i][j]=MaxWeight; //MaxWeight 表示无穷大 }

G->numOfEdges=0; //边的条数置为0 ListInitiate(&G->Vertices); //顺序表初始化 }

/**在图中增加一个顶点**/

void InsertVertex(AdjMGraph *G, DataType vertex) //在图中插入顶点vertex {

ListInsert(&G->Vertices,G->Vertices.size,vertex); //顺序表尾插入 }

/**在图中增加一条有向边**/

void InsertEdge(AdjMGraph *G, int v1, int v2, int weight)

//在图G 中插入边,边的权为weight {

if(v1 = G->Vertices.size || v2 = G->Vertices.size) {

printf("参数v1或v2越界出错!\n"); return; }

G->edge[v1][v2] =weight; G->numOfEdges++; }

/**在图中取消一条有向边**/

void DeleteEdge(AdjMGraph *G,int v1,int v2) //在图G 中删除边

if(v1 = G->Vertices.size || 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 的顶点的第一个邻接顶点

//如果这样的邻接顶点存在,则返回该邻接顶点的序号,否则返回-1 {

int col;

if(v = G.Vertices.size) {

printf("参数v1越界!\n"); return -1; }

for(col = 0; col

if(G.edge[v][col]>0&&G.edge[v][col]

return -1; }

/**取下一个邻接顶点**/

int GetNextVex(AdjMGraph G,int v1, int v2)

//在图G 中寻找V1顶点的邻接顶点V2的下一个邻接顶点 {

int col;

if(v1 = G.Vertices.size || v2 = G.Vertices.size) {

printf("参数v1或v2越界出错!\n"); return -1; }

for(col=v2+1;col

if(G.edge[v1][col]>0&&G.edge[v1][col]

return -1; }

#endif // ADJMGRAPH_H_INCLUDED

2. 子函数AdjMGraphCreate.h

/**图的创建函数**/

#ifndef ADJMGRAPHCREATE_H_INCLUDED #define ADJMGRAPHCREATE_H_INCLUDED

typedef struct {

int row; //行下标 int col; //列下标 int weight; //权值

}RowColWeight; //边信息结构体定义

void CreatGraph(AdjMGraph *G,DataType V[],int n,RowColWeight E[],int e) //在图G 中出入n 个顶点信息V 和e 条边的信息E {

int i,k;

Initiate(G,n); //顶点顺序表初始化

for(i=0;i

InsertVertex(G,V[i]); //插入顶点

for(k=0;k

InsertEdge(G,E[k].row,E[k].col,E[k].weight); //插入边

}

#endif // ADJMGRAPHCREATE_H_INCLUDED

3. 子函数Dijkstra.h

#ifndef DIJKSTRA_H_INCLUDED #define DIJKSTRA_H_INCLUDED #define N 6

void Dijkstra(AdjMGraph G, int v1, int distance[], int path[][N])

//带权图G 从下标v1顶点到其他顶点的最短距离distance 和最短路径下标path {

int n=G.Vertices.size;

int *s=(int*)malloc(sizeof(int)*n); int minDis,i,j,u,k;

//初始化

for(i=0;i

path[i][0]=v1; for(j=1;j

for(i=0;i

distance[i]=G.edge[v1][i]; s[i]=0;

if(i!=v1&&distance[i]

//标记顶点v0已从集合T 加入到集合S 中 s[v1]=1;

//在当前还未找到最短路径的顶点集中选取具有最短距离的顶点u for(i=1;i

minDis=MaxWeight;

for(j=0;j

if(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

#ifndef SeqList_H #define SeqList_H

typedef struct { DataType list[MaxSize]; // DataType这个在你用的时候可以去定义它的类型 int size; //指这个表的总长度

}SeqList; //定义抽象数据类型SeqList

void ListInitiate(SeqList *L) // 初始化顺序表L { L->size=0; // 定义初始元素个数 }

int ListLength(SeqList L)

{

return L.size;

}

int ListInsert(SeqList *L,int i,DataType x)

//在顺序表L 的位置i (0

{

int j;

if(L->size >= MaxSize)

{

printf("表已满无法插入!\n");

return 0;

}

else if(iL->size)

{

printf("参数i 不合法!\n");

return 0;

}

else

{

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)

//删除顺序表L 中位置i 上的数据元素并保存到x 中

//插入成功返回1,否则返回0

{

int j;

if(L->size

{

printf("表已空无法插入!\n");

return 0;

}

else if(iL->size-1)

{

printf("参数i 不合法!\n");

return 0;

}

else

{

*x=L->list[i];

for(j=i+1;jsize-1;j++)

L->list[j-1]=L->list[j];

L->size--;

return 1;

}

}

int ListGet(SeqList L,int i,DataType *x)

//取顺序表L 中第i 个元素的值,取到则返回1,否则返回0

{

if(iL.size-1)

{

printf("参数i 不合法!\n");

return 0;

}

else

{

*x=L.list[i];

return 1;

}

}

int ListNotEmpty(SeqList L)

//判断该表是否为空

//如果表的总长度小于等于0,则说明该表为空,返回1

{

if(L.size

return 0;

else

return 1;

}

#endif

5. 主函数

#include

#include

#include

typedef char DataType;

#define MaxSize 10 //定义顺序表数组的最大值 #define MaxVertices 30 //定义顶点的最大值 #define MaxWeight 10000 // 定义无穷大的具体值

#include "AdjMGraph.h"

#include "AdjMGraphCreate.h"

#include "Dijkstra.h"

int main()

{

AdjMGraph g;

char a[]={'1','2','3','4','5','6'};

RowColWeight rcw[]={{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}}; int i, n=6, e=11,j;

int distance[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;i

printf("到顶点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;j

if(path[i][j]!=-1)

printf (" v%c ",g.Vertices.list[path[i][j]]);

}

return 0;

}

九、测试情况

程序运行结果

单源结点最短路径

一、题目

单源结点最短路径问题。

二、问题描述

求从有向图的某一结点出发到其余各结点的最短路径。

三、基本要求

(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 图结构如下图所示:

2. 求最短路径和最短距离

算法流程图

(1)求得最短距离矩阵如下

⎡0-1-1-1⎢01-1-1⎢

⎢02-1-1

path [6][6]=⎢

⎢0253⎢0253⎢

⎢025-1⎣

-1-1⎤

-1-1⎥⎥-1-1⎥

-1-1⎥4-1⎥

-1-1⎦⎥

(2)求得最短距离矩阵如下

distance [6]=[[1**********]]

七、数据结构

1. 结构体定义

(1)图的结构体定义

typedef struct {

SeqList Vertices; //存放顶点的顺序表 int edge[MaxVertices][MaxVertices]; //存放边的邻接矩阵 int numOfEdges; }AdjMGraph; (2)边信息结构体定义 typedef struct {

int row; int col;

int weight; }RowColWeight;

八、源程序

1. 子函数AdjMGraph.h

/**邻接矩阵存储存储结构下图操作的实现**/

#ifndef ADJMGRAPH_H_INCLUDED #define ADJMGRAPH_H_INCLUDED

#include "SeqList.h"

typedef struct {

SeqList Vertices; int edge[MaxVertices][MaxVertices]; int numOfEdges; }AdjMGraph;

/**初始化有n 个顶点的顶点顺序表和邻接矩阵**/

//边的条数 //图的结构体定义 //行下标 //列下标 //权值

//边信息结构体定义

//包含顺序表头文件 //存放顶点的顺序表 //存放边的邻接矩阵 //边的条数

//图的结构体定义

void Initiate(AdjMGraph *G, int n) {

int i,j;

for(i=0;i

for(j=0;j

if(i==j) G->edge[i][j]=0;

else G->edge[i][j]=MaxWeight; //MaxWeight 表示无穷大 }

G->numOfEdges=0; //边的条数置为0 ListInitiate(&G->Vertices); //顺序表初始化 }

/**在图中增加一个顶点**/

void InsertVertex(AdjMGraph *G, DataType vertex) //在图中插入顶点vertex {

ListInsert(&G->Vertices,G->Vertices.size,vertex); //顺序表尾插入 }

/**在图中增加一条有向边**/

void InsertEdge(AdjMGraph *G, int v1, int v2, int weight)

//在图G 中插入边,边的权为weight {

if(v1 = G->Vertices.size || v2 = G->Vertices.size) {

printf("参数v1或v2越界出错!\n"); return; }

G->edge[v1][v2] =weight; G->numOfEdges++; }

/**在图中取消一条有向边**/

void DeleteEdge(AdjMGraph *G,int v1,int v2) //在图G 中删除边

if(v1 = G->Vertices.size || 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 的顶点的第一个邻接顶点

//如果这样的邻接顶点存在,则返回该邻接顶点的序号,否则返回-1 {

int col;

if(v = G.Vertices.size) {

printf("参数v1越界!\n"); return -1; }

for(col = 0; col

if(G.edge[v][col]>0&&G.edge[v][col]

return -1; }

/**取下一个邻接顶点**/

int GetNextVex(AdjMGraph G,int v1, int v2)

//在图G 中寻找V1顶点的邻接顶点V2的下一个邻接顶点 {

int col;

if(v1 = G.Vertices.size || v2 = G.Vertices.size) {

printf("参数v1或v2越界出错!\n"); return -1; }

for(col=v2+1;col

if(G.edge[v1][col]>0&&G.edge[v1][col]

return -1; }

#endif // ADJMGRAPH_H_INCLUDED

2. 子函数AdjMGraphCreate.h

/**图的创建函数**/

#ifndef ADJMGRAPHCREATE_H_INCLUDED #define ADJMGRAPHCREATE_H_INCLUDED

typedef struct {

int row; //行下标 int col; //列下标 int weight; //权值

}RowColWeight; //边信息结构体定义

void CreatGraph(AdjMGraph *G,DataType V[],int n,RowColWeight E[],int e) //在图G 中出入n 个顶点信息V 和e 条边的信息E {

int i,k;

Initiate(G,n); //顶点顺序表初始化

for(i=0;i

InsertVertex(G,V[i]); //插入顶点

for(k=0;k

InsertEdge(G,E[k].row,E[k].col,E[k].weight); //插入边

}

#endif // ADJMGRAPHCREATE_H_INCLUDED

3. 子函数Dijkstra.h

#ifndef DIJKSTRA_H_INCLUDED #define DIJKSTRA_H_INCLUDED #define N 6

void Dijkstra(AdjMGraph G, int v1, int distance[], int path[][N])

//带权图G 从下标v1顶点到其他顶点的最短距离distance 和最短路径下标path {

int n=G.Vertices.size;

int *s=(int*)malloc(sizeof(int)*n); int minDis,i,j,u,k;

//初始化

for(i=0;i

path[i][0]=v1; for(j=1;j

for(i=0;i

distance[i]=G.edge[v1][i]; s[i]=0;

if(i!=v1&&distance[i]

//标记顶点v0已从集合T 加入到集合S 中 s[v1]=1;

//在当前还未找到最短路径的顶点集中选取具有最短距离的顶点u for(i=1;i

minDis=MaxWeight;

for(j=0;j

if(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

#ifndef SeqList_H #define SeqList_H

typedef struct { DataType list[MaxSize]; // DataType这个在你用的时候可以去定义它的类型 int size; //指这个表的总长度

}SeqList; //定义抽象数据类型SeqList

void ListInitiate(SeqList *L) // 初始化顺序表L { L->size=0; // 定义初始元素个数 }

int ListLength(SeqList L)

{

return L.size;

}

int ListInsert(SeqList *L,int i,DataType x)

//在顺序表L 的位置i (0

{

int j;

if(L->size >= MaxSize)

{

printf("表已满无法插入!\n");

return 0;

}

else if(iL->size)

{

printf("参数i 不合法!\n");

return 0;

}

else

{

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)

//删除顺序表L 中位置i 上的数据元素并保存到x 中

//插入成功返回1,否则返回0

{

int j;

if(L->size

{

printf("表已空无法插入!\n");

return 0;

}

else if(iL->size-1)

{

printf("参数i 不合法!\n");

return 0;

}

else

{

*x=L->list[i];

for(j=i+1;jsize-1;j++)

L->list[j-1]=L->list[j];

L->size--;

return 1;

}

}

int ListGet(SeqList L,int i,DataType *x)

//取顺序表L 中第i 个元素的值,取到则返回1,否则返回0

{

if(iL.size-1)

{

printf("参数i 不合法!\n");

return 0;

}

else

{

*x=L.list[i];

return 1;

}

}

int ListNotEmpty(SeqList L)

//判断该表是否为空

//如果表的总长度小于等于0,则说明该表为空,返回1

{

if(L.size

return 0;

else

return 1;

}

#endif

5. 主函数

#include

#include

#include

typedef char DataType;

#define MaxSize 10 //定义顺序表数组的最大值 #define MaxVertices 30 //定义顶点的最大值 #define MaxWeight 10000 // 定义无穷大的具体值

#include "AdjMGraph.h"

#include "AdjMGraphCreate.h"

#include "Dijkstra.h"

int main()

{

AdjMGraph g;

char a[]={'1','2','3','4','5','6'};

RowColWeight rcw[]={{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}}; int i, n=6, e=11,j;

int distance[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;i

printf("到顶点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;j

if(path[i][j]!=-1)

printf (" v%c ",g.Vertices.list[path[i][j]]);

}

return 0;

}

九、测试情况

程序运行结果


相关内容

  • 最小生成树and最短路径
  • 最小生成树and 最短路径 无独有偶,在两个学期的期末中两门不同的科目<离散数学>和<数据结构>中都谈到了图及其衍生的最小生成树.最短路径问题,并给出了相应的算法--克鲁斯卡尔.普林.迪杰斯特拉.沃舍尔算法.这无疑是释放了一个很大的信号--这些内容很重要.由于之前学<离 ...

  • 数据结构考研真题
  • 2009数据结构真题 1,为解决计算机与打印机之间速度不匹配的问题,通常设置一个打印数据缓冲区,主机将要输出的数据依次写入该缓冲区,而打印机则依次从该缓冲区中取出数据.该缓冲区的逻辑结构应该是 A. 栈 B. 队列 C. 树 D. 图 解答: B 先入先出,满足队列特性 2. 设栈S 和队列Q 的初 ...

  • 分枝限界法_实验报告
  • 一.课题名称 用分枝限界法求解单源最短路径问题 二.课题内容和要求 设计要求:学习算法设计中分枝限界法的思想,设计算法解决数据结构中求解单源最短路径问题,编程实现: (1)给出指定源点的单源最短路径: (2)说明算法的时间复杂度. 三.需求分析 1.实现极小堆的创建,用来存储活结点表. 2.实现循环 ...

  • 一种交流负反馈组态的快速判断方法
  • 第19卷 第7期 牡丹江大学学报 Vol.19 No.7 2010年7月 Journal of Mudanjiang University Jul. 2010 文章编号:1008-8717(2010)07-0105-03 一种交流负反馈组态的快速判断方法 徐淑武 黄云霞 (南通大学理学院,江苏 南通 ...

  • 图论算法(经典)
  • 图论算法 最小生成树算法(Prim算法) 单源最短路径算法(Dijkstra算法) 任意结点最短路径算法(Floyd算法) 求有向带权图的所有环 Bellman-Ford 算法 计算图的连通性 计算最佳连通分支 计算拓扑序列 图论算法习题 网络建设问题 最短变换问题 挖地雷 乌托邦城市 乌托邦交通中 ...

  • 分支界限法.
  • 武汉理工大学 算法设计与分析论文 题 目: 分支限界法应用研究 目 录 摘 要 . ...................................................... 1 1. 绪 论 . .......................................... ...

  • 3.GB/T12326-2008电能质量 电压波动和闪变
  • 电能质量 电压波动和闪变 Power quality-Voltage fluctuation and flicker GB12326-2000 代替GB12326-1990 前 言 本标准是电能质量系列标准之一,目前已制定颁布的电能质量系列国家标准有:<供电电压允许偏差>(GB 1232 ...

  • 最短路径问题设计论文
  • 目 录 第1章 绪论 ........................................................................................................................................... ...

  • 模拟电路学过的电路分析方法
  • 模拟电路的分析方法 一. 集成运放组成模拟运算电路的分析方法 方法一:结点电流法 1)选取结点(一般选取与"+"或"-"相接的结点): 2)任意选取与结点有关支路的电流参考方向: 3)列KCL 方程: 4)利用集成运放的特点:虚短.虚断: 5)确定 V + = ...