最短路径Dijkstra算法

Dijkstra算法是一个求最短路径的算法

作用:求图中一点到图的其他所有点的最短路径,要求路径全为正的,不能有负值

时间复杂度:O(V^2)

空间复杂度:O(V)
算法步骤详解:

a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为无穷大。

b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。

c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。

d.重复步骤b,c直到所有的定点都包括在S集合中。

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
#define MaxSize 20
#define INFINITY 65535
 
typedef char VertexType;
 
 //定义图 的邻接矩阵表示法结构
typedef struct Graph {
	VertexType ver[MaxSize+1];
	int edg[MaxSize][MaxSize];
}Graph;
 
//邻接矩阵法图的生成函数
void CreateGraph( Graph *g )
{
	int i = 0;
	int j = 0;
	int VertexNum;
	VertexType Ver;
 
	printf("请输入图的顶点:\n");
	while( '\n' != (Ver=getchar()) )
		g->ver[i++] = Ver;
	g->ver[i] = '\0';
 
	VertexNum = strlen(g->ver);
	printf("请输入相应的的邻接矩阵:\n");
	for( i=0; i<VertexNum; i++ )
		for( j=0; j<VertexNum; j++ )
			scanf("%d", &g->edg[i][j]);
}
 
//打印图的结点标识符和邻接矩阵
void PrintGraph( Graph g )
{
	int i, j;
	int VertexNum = strlen(g.ver);
	printf("图的顶点为:\n");
	for( i=0; i<VertexNum; i++ )
		printf("%c ", g.ver[i]);
	printf("\n");
 
	printf("图的邻接矩阵为:\n");
	for( i=0; i<VertexNum; i++ ) {
		for( j=0; j<VertexNum; j++ )
			printf("%d ", g.edg[i][j]);
		printf("\n");
	}
}
 
//求图的顶点数
int CalVerNum( Graph g )
{
	return strlen(g.ver);
}
 
//将不邻接的顶点之间的权值设置为INFINITY
void SetWeight( Graph *g )
{
	for( int i=0; i<CalVerNum(*g); i++ )
		for( int j=0; j<CalVerNum(*g); j++ )
			if( 0 == g->edg[i][j] )
				g->edg[i][j] = INFINITY;
}
 
//Dijkstra求最短路径函数
void Dijkstra( Graph g )
{
	int VertexNum = CalVerNum( g );
	int j;
	int mini;
	int index = 0;
	int *used = (int *)malloc(sizeof(int)*VertexNum);
	int *distance = (int *)malloc(sizeof(int)*VertexNum);
	int *parent = (int *)malloc(sizeof(int)*VertexNum);
	int *last = (int *)malloc(sizeof(int)*VertexNum);
 
	SetWeight( &g );					//设置权值
 
	for( int i=0; i<VertexNum; i++ ) {
		used[i] = 0;
		distance[i] = g.edg[0][i];   //初始化为与编号为0的顶点的距离
		last[i] = 0;
	}
 
	used[0] = 1;
	parent[index++] = 0;
	int i; 
	for( i=0; i<VertexNum-1; i++ ) 
	{
		j = 0;
		mini = INFINITY;
 
		for( int k=0; k<VertexNum; k++ )
			if( (0 == used[k]) && (distance[k] < mini) ) {
				mini = distance[k];
				j = k;			//j为刚刚找到的V-U中到源点路径最短的顶点
			}
		
		used[j] = 1;
 		int k;
		for( k=0; k<VertexNum; k++ ) 
			if( (0 == used[k]) && (distance[k] > distance[j] + g.edg[j][k]) ) {   //由于有顶点新加入U集合,对距离数组distance进行更新,比较原路径长度与以新加入的顶点为中间点的路径长度
				distance[k] = distance[j] + g.edg[j][k];
			}
 
		parent[index++] = j;
	}
 
	printf("%c到%c的最短路径经过顶点依次为:\n", g.ver[0], g.ver[VertexNum-1]);
	for( i=0; i<index; i++ )
		printf("%c ", g.ver[parent[i]]);
	printf("\n");
 
	printf("最短路径长度为: %d\n", mini);
	
}
 
int main()
{
	Graph g;
	CreateGraph( &g );
	PrintGraph( g );
 
	Dijkstra( g );
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值