最短路径与Dijkstra算法

给定一个有向图G和起点S,如何求出图中S到其中所有点的最短路径呢?Dijkstra给出了一个比较好的算法,它的基本步骤如下:
1.计算起点s到所有节点的距离。
2.挑出其中距离最小的节点smin。(如果这个节点已经被调过了,就不再选它了)
3.利用这个节点更新起点到其他节点的最小距离:如果s到smin的直接距离+smin到其他节点某个节点的直接距离 < s到其他某个节点的直接距离,那么就用s到smin的直接距离+smin到其他某个节点的直接距离代替s到其他某个节点的直接距离。
4.不断重复2、3直到只剩下一个节点。

为了实现上述功能,我特意在图的数据结构中加入两个数组:hasUsed表示这个节点是否被使用,而length记录了起点到各个节点的距离:

#include <stdio.h>
#include <malloc.h>
#include <limits.h>

typedef int** ADJACENTMATRIX;
typedef struct directedAcyclineGraph
{
	ADJACENTMATRIX matrix;
	int vertexNumber;
	int arcNumber;
	char* vertex;
	bool* hasUsed;
	//记录起点到每个节点的距离
	int* length;
}DAG;

#define MAX 8
//基本操作
//初始化
DAG initGraph(int);
//销毁
void destroyGraph(DAG* );
//添加
bool addArc(DAG* ,char,char,int);
//删除
bool deleteArc(DAG* ,char,char);
//打印邻接矩阵
void printGraph(DAG* );

//Dijkstra算法相关函数
void initLengthVector(DAG* ,int );
int selectShortestLengthNode(DAG* );
void Dijkstra(DAG* ,char );


 

DAG initGraph(int n)
{
	DAG g;
	g.vertexNumber = n;
	g.arcNumber = 0;
	g.vertex = (char*)malloc(sizeof(char) * n);
	g.hasUsed = (bool*)malloc(sizeof(bool) * n);
	g.length = (int*)malloc(sizeof(int) * n);
	char start = 'A';
	for(int i = 0; i < n;++i)
	{
		g.vertex[i] = start + i;
		g.hasUsed[i] = false;
		g.length[i] = INT_MAX;
	}
	g.matrix = (int**)malloc(sizeof(int*) * n);
	for(int i = 0; i < n;++i)
		g.matrix[i] = (int*)malloc(sizeof(int) * n);
	//邻接矩阵的初始为为最大值
	for(int i = 0; i < n;++i)
		for(int j = 0; j < n;++j)
			g.matrix[i][j] = INT_MAX;
	return g;
}

void destroyGraph(DAG* g)
{
	free(g->vertex);
	free(g->hasUsed);
	free(g->length);
	g->vertex = NULL;
	g->hasUsed = NULL;
	g->length = NULL;
	
	for(int i = 0; i < g->vertexNumber;++i)
		free(g->matrix[i]);
	free(g->matrix);
	g->matrix = NULL;
	g->arcNumber = -1;
	g->vertexNumber = -1;
}

bool addArc(DAG* g,char start,char end,int w)
{
	int i = start - 'A';
	int j = end - 'A';
	if(i < 0 || i > g->vertexNumber || j < 0 || j > g->vertexNumber)
	{
		printf("vertexes does not exsist!\n");
		return false;
	}
	else
	{
		g->matrix[i][j] = w;	
		g->arcNumber++;
		return true;
	}
}

bool deleteArc(DAG* g,char start,char end)
{
	int i = start - 'A';
	int j = end - 'A';
	if(i < 0 || i > g->vertexNumber || j < 0 || j > g->vertexNumber)
	{
		printf("vertexes does not exsist!\n");
		return false;
	}
	if(INT_MAX == g->matrix[i][j] )
	{
		printf("there is no arc between vertexes!\n");
		return false;
	}
	else
	{
		g->matrix[i][j] = INT_MAX;
		g->arcNumber--;
		return true;
	}	
}


void printGraph(DAG* g)
{
	printf("     ");
	for(int i = 0 ; i < g->vertexNumber;++i)
		printf("%-4c ",g->vertex[i]);

	for(int i = 0; i < g->vertexNumber;++i)
	{
		printf("\n");
		printf("%-4c ",g->vertex[i]);
		for(int j = 0; j < g->vertexNumber;++j)
		{
			if(INT_MAX == g->matrix[i][j]  )
				printf("NULL ");
			else
				printf("%-4d ",g->matrix[i][j]);
		}
			
	}
	printf("\n");
}

//程序的工作是计算起始点到所有节点的最短距离
//并输出路径
void Dijkstra(DAG* g,char Start)
{
	int start = Start - 'A';
	g->hasUsed[start] = true;
	int cnt = g->vertexNumber;
	//初始化距离长度数组
	initLengthVector(g,start);
	while(cnt > 1)
	{
		int miniNode = selectShortestLengthNode(g);
//		printf("挑出的节点为%d\n",miniNode);
		//更新length数组
		for(int i = 0; i < g->vertexNumber;++i)
		{
			if(i == start || i == miniNode) 
				continue;
			//计算原路径长度和使用新增加一个节点作为过渡节点后的长度
			if(g->length[i] > g->length[miniNode] + g->matrix[miniNode][i])
			{
				//注意:INT_MAX = 2147483647
				//2147483647 > 2147483647+10因为2147483647+10为一个负数
				if(INT_MAX == g->matrix[miniNode][i] || INT_MAX == g->length[miniNode])
					;//什么也不做
				else
					g->length[i] = g->length[miniNode] + g->matrix[miniNode][i];
			}
		}
		--cnt;

	}
	//输出到各个节点的长度
	for(int i = 0; i < g->vertexNumber;++i)
	{
		if(start == i)
			continue;
		if(INT_MAX == g->length[i])
			printf("节点%c不可到达\n",g->vertex[i]);
		else
			printf("到节点%c距离为:%d\n",g->vertex[i],g->length[i]);
	}

}

void initLengthVector(DAG* g,int start)
{
	for(int i = 0; i < g->vertexNumber;++i)
	{
		if(i == start)
			continue;
		g->length[i] = g->matrix[start][i];
	}
}

int selectShortestLengthNode(DAG* g)
{
	int shortestPath = INT_MAX;
	int vertex = 0;
	for(int i = 0; i < g->vertexNumber;++i)
	{
		if(true == g->hasUsed[i] )
			continue;
		if(shortestPath > g->length[i])
		{
			shortestPath = g->length[i];
			vertex = i;
		}
	}
	g->hasUsed[vertex] = true;
	return vertex;
}


 程序中还有一定需要注意的是,因为INT_MAX = 2147483647,所以INT_MAX加上一个数会发生越界的情况,导致值为负数,这是我们不想出现的情况,需要避免。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值