图的最短路径--Dijkstra算法与Floyd算法

1. 单源最短路径——迪杰斯特拉(Dijkstra)算法

1.1 算法思想

(1)初始化:先找出从源点V0到各终点Vk的直达路径(V0,Vk),即通过一条弧到达的路径。
(2)选择:从这些路径中找出一条长度最短的路径(V0,U)。
(3)更新:然后对其余各条路径进行适当调整:
若在图中存在弧(U,Vk),且(V0,U)+(U,Vk)<(V0,Vk),
则以路径(V0,U,Vk)代替(V0,Vk)。
(4)在调整后的各条路径中,再找长度最短的路径,以此类推。

迪杰斯特拉(Dijkstra)算法:按路径长度递增次序产生最短路径

1、把V分成两组:
(1)S:已求出最短路径的顶点的集合。
(2)T=V-S:尚未确定最短路径的顶点集合。
2、将T中顶点按最短路径递增的次序加入到S中,
保证
(1)从源点V0到S中各顶点的最短路径长度都不大于从V0到T中任何顶点的最短路径长度。
(2)每个顶点对应一个距离值
S中顶点:从V0到此顶点的最短路径长度。
T中顶点:从V0到此顶点的只包括S中顶点作中间顶点的最短路径长度。

算法复杂度:O(n^2)

1.2 代码

#include 
using namespace std;

/**************************************************************************************
*********************************** 图结构定义及操作 ************************************
***************************************************************************************/
typedef char VertexType;	// 顶点类型,自定义
typedef int  WeightType;	// 边上权值类型,自定义

#define MAXVEX		(100)	// 最大顶点数
#define INFINITY	(65535)	// 用65535表示∞,表示顶点之间没有边

typedef struct {
	VertexType vexs[MAXVEX];			// 顶点数组
	WeightType arcs[MAXVEX][MAXVEX];	// 邻接矩阵
	int Nv, Ne;							// 顶点数、边数
} MGraph;

/**
* @brief:	建立图的邻接矩阵结构
* @param G:指向图的指针
* @return:	void
*/
void createMGraph(MGraph* G) {
	cout << "输入顶点数和边数:";
	cin >> G->Nv >> G->Ne;

	// 初始化邻接矩阵
	for (int i = 0; i < G->Nv; i++)
	{
		for (int j = 0; j < G->Nv; j++)
		{
			G->arcs[i][j] = (i == j) ? 0 : INFINITY;	// 邻接矩阵主对角线初始化为0,其余初始化为INFINITY
		}
	}

	cout << "输入顶点信息:";
	for (int i = 0; i < G->Nv; i++)
	{
		cin >> G->vexs[i];
	}

	// 读入Ne条边信息,建立邻接矩阵
	int i, j;
	WeightType w;
	for (int k = 0; k < G->Ne; k++)
	{
		cout << "输入边(Vi, Vj)的下标i、j及其权值w:";
		cin >> i >> j >> w;
		G->arcs[i][j] = w;
		G->arcs[j][i] = G->arcs[i][j];	// 无向图的邻接矩阵为对称阵
	}
}

/**************************************************************************************
********************************* 最短路径之Dijkstra算法 ********************************
***************************************************************************************/

typedef int Patharc[MAXVEX];		// 用于存储最短路径下标(前驱顶点的下标)的数组
typedef int ShortPathTable[MAXVEX];	// 用于存储到各点最短路径的权值和

/**
* @brief:	Dijkstra算法,求v0顶点到其余顶点v的最短路径P[v]及带权长度D[v]
*			P[v]的值为前驱顶点下标,D[v]表示v0到v的最短路径权值和
* @param G: 图
* @param v0:顶点v0下标
* @param P:	记录最短路径下标的数组
* @param D:	记录最短路径权值和的数组
* @return: void
*/
void ShortestPath_Dijkstra(MGraph G, int v0, Patharc P, ShortPathTable D)
{
	/* 初始化 P、D、辅助状态数组final */
	int v, w, k, min;
	int final[MAXVEX];	// final[w]=1表示已经求得v0值vw的最短路径
	for (v = 0; v < G.Nv; v++)
	{
		final[v] = 0;			// 全部顶点初始化为未知最短路径状态
		P[v] = 0;				// 初始化路径数组P为0
		D[v] = G.arcs[v0][v];	// 初始化路径权值和数组D为v0至各其余顶点v的权值
	}
	
	D[v0] = 0;		// v0至v0的路径长度为0,实际可不用,因为上面for循环已将其赋值0
	final[v0] = 1;	// v0至v0不需要求路径

	/* 主循环,每次求得v0到某个v顶点的最短路径 */
	for (v = 0; v < G.Nv; v++)
	{
		min = INFINITY;
		for (w = 0; w < G.Nv; w++)
		{
			if (!final[w] && D[w] < min)
			{
				min = D[w];		// w顶点离v0顶点更近
				k = w;			// 记录w顶点
			}
		}
		
		final[k] = 1;			// 将目前找到的最近顶点对应的final位置处置1
		for (w = 0; w < G.Nv; w++)
		{
			// 如果经过k顶点的路径比现在这条路径长度短的话,更新D[w]和P[w]
			if (!final[w] && min + G.arcs[k][w] < D[w])
			{
				D[w] = min + G.arcs[k][w];
				P[w] = k;
			}
		}
	}
}


int main()
{
	MGraph* G = new MGraph;
	createMGraph(G);

	Patharc P;
	ShortPathTable D;
	ShortestPath_Dijkstra(*G, 0, P, D);

	cout << "\n数组P: " << endl;
	for (size_t i = 0; i < G->Nv; i++)
	{
		cout << P[i] << "\t";
	}

	cout << "\n数组D: " << endl;
	for (size_t i = 0; i < G->Nv; i++)
	{
		cout << D[i] << "\t";
	}

	delete G;
}

运行结果:
以《大话数据结构》图7-7-3为例。
图的最短路径--Dijkstra算法与Floyd算法_第1张图片

2. 所有顶点间的最短路径——弗洛伊德(Floyd)算法

方法一:每次以一个顶点为源点,重复执行Dijkstra算法n次。
方法二:弗洛伊德(Floyd)算法。

2.1 算法思想

算法思想:逐个顶点试探,从Vi到Vj的所有可能存在的路径中,选出一条长度最短的路径。

求最短路径步骤:
初始化时设置一个n阶方阵,令其对角线元素为0,若存在弧,则对应元素为权值,否则为∞;(邻接矩阵)
逐步试着在原直接路径中增加中间顶点,若加入中间顶点后路径变短,则修改之;否则,维持原值;
所有顶点试探完毕,算法结束。

2.2 代码

#include 
using namespace std;

/**************************************************************************************
*********************************** 图结构定义及操作 ***********************************
***************************************************************************************/
typedef char VertexType;	// 顶点类型,自定义
typedef int  WeightType;	// 边上权值类型,自定义

#define MAXVEX		(100)	// 最大顶点数
#define INFINITY	(65535)	// 用65535表示∞,表示顶点之间没有边

typedef struct {
	VertexType vexs[MAXVEX];			// 顶点数组
	WeightType arcs[MAXVEX][MAXVEX];	// 邻接矩阵
	int Nv, Ne;							// 顶点数、边数
} MGraph;

/**
* @brief:	建立图的邻接矩阵结构
* @param G:指向图的指针
* @return:	void
*/
void createMGraph(MGraph* G) {
	cout << "输入顶点数和边数:";
	cin >> G->Nv >> G->Ne;

	// 初始化邻接矩阵
	for (int i = 0; i < G->Nv; i++)
	{
		for (int j = 0; j < G->Nv; j++)
		{
			G->arcs[i][j] = (i == j) ? 0 : INFINITY;	// 邻接矩阵主对角线初始化为0,其余初始化为INFINITY
		}
	}

	cout << "输入顶点信息:";
	for (int i = 0; i < G->Nv; i++)
	{
		cin >> G->vexs[i];
	}

	// 读入Ne条边信息,建立邻接矩阵
	int i, j;
	WeightType w;
	for (int k = 0; k < G->Ne; k++)
	{
		cout << "输入边(Vi, Vj)的下标i、j及其权值w:";
		cin >> i >> j >> w;
		G->arcs[i][j] = w;
		G->arcs[j][i] = G->arcs[i][j];	// 无向图的邻接矩阵为对称阵
	}
}

/**************************************************************************************
********************************* 最短路径之Floyd算法 **********************************
***************************************************************************************/
typedef int Pathmatrix[MAXVEX][MAXVEX];
typedef int ShortPathTable[MAXVEX][MAXVEX];

/**
@brief:		Floyd算法,求图G中各顶点v到其余顶点w最短路径P[v][w]及带权长度D[v][w]
@param G:	图
@param P:	记录最短路径下标的二维数组
@param D:	记录最短路径权值和的二维数组
#return:	void
*/
void ShortestPath_Floyd(MGraph G, Pathmatrix P, ShortPathTable D)
{
	int v, w, k;
	/* 初始化P和D */
	for (v = 0; v < G.Nv; v++)
	{
		for (w = 0; w < G.Nv; w++)
		{
			D[v][w] = G.arcs[v][w];		// 初始化为邻接矩阵对应的权值
			P[v][w] = w;
		}
	}

	/* 算法主循环 */
	for (k = 0; k < G.Nv; k++)
	{
		for (v = 0; v < G.Nv; v++)
		{
			for (w = 0; w < G.Nv; w++)
			{	
				// 如果经过下标为k的顶点路径比原两点间路径更短,更新
				if (D[v][w] > D[v][k] + D[k][w])
				{
					D[v][w] = D[v][k] + D[k][w];
					P[v][w] = P[v][k];		// 路径设置经过下标为k的顶点
				}
			}
		}
	}
}

int main()
{
	MGraph* G = new MGraph;
	createMGraph(G);

	Pathmatrix P;
	ShortPathTable D;
	ShortestPath_Floyd(*G, P, D);

	cout << "\n数组P: " << endl;
	for (size_t i = 0; i < G->Nv; i++)
	{
		for (size_t j = 0; j < G->Nv; j++)
		{
			cout << P[i][j] << "\t";
		}
		cout << endl;
	}

	cout << "\n数组D: " << endl;
	for (size_t i = 0; i < G->Nv; i++)
	{
		for (size_t j = 0; j < G->Nv; j++)
		{
			cout << D[i][j] << "\t";
		}
		cout << endl;
	}

	delete G;
}

运行结果:
以《大话数据结构》图7-7-3为例。
图的最短路径--Dijkstra算法与Floyd算法_第2张图片

3. 参考书籍

大话数据结构-程杰
青岛大学数据结构-王卓

你可能感兴趣的:(数据结构与算法,图论,算法,数据结构)