Dijkstra 算法的 C/C++ 实现

Dijkstra算法 Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,是广度优先算法的一种,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。其基本原理是:每次新扩展一个距离最短的点,更新与其相邻的点的距离。当所有边权都为正时,由于不会存在一个距离更短的没扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。不过根据这个原理,用Dijkstra求最短路的图不能有负权边,因为扩展到负权边的时候会产生更短的距离,有可能就破坏了已经更新的点距离不会改变的性质。 Dijkstra算法能得出最短路径的最优解,但由于它遍历计算的节点很多,所以效率低。   Dijkstra算法是很有代表性的最短路算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。

Dijkstra 算法的时间复杂度为O(n^2)   空间复杂度取决于存储方式,邻接矩阵为O(n^2)

先上代码:

// Dijkstra.cpp : 定义控制台应用程序的入口点。
//

#include 
#include 
#include 
using namespace::std;

#define INF 0x7fffffff
#define maxN 50
#pragma warning(disable:4996)

#define USE_C 1
#define NOT_USE_C 0

#define USE_CPP 1

int matrix[maxN][maxN];
// C++实现
void Dijkstra_cpp(vector>&vec, vector& result, int v0){
	vector visited(vec.size(), 0); // 表示顶点是否被选中,0:顶点未被选中;1:顶点已被选中
	int last_visited = 0;
	visited[v0] = 1; // 选中起始顶点
	result[0] = 0;

	for (int i = 0; i < vec.size() - 1; ++i) { // N 个顶点需要做 N - 1 次循环
		// 查看顶点周围的所有点
		for (int j = 0; j < vec.size(); ++j) { // 循环遍历所有顶点
			if (visited[j] == 0){ // 保证被查看的新顶点没有被访问到
				if (vec[v0][j] != 0){ // 保证当前顶点(V0)与新顶点(j)之间有路径
					int dist = vec[v0][j] + last_visited; // 计算 V0 到 J 的路径距离
					if (dist < result[j])result[j] = dist; // 用新路径代替原来的路径
				}
			}
		}
		// 找出最小值
		int minIndex = 0;
		while (visited[minIndex] == 1) minIndex++; // 找第一个没有被选中的节点
		for (int j = minIndex; j < vec.size(); ++j) {
			if (visited[j] == 0 && result[j] < result[minIndex]){
				minIndex = j;
			}
		}

		last_visited = result[minIndex]; // 更新最小值
		visited[minIndex] = 1; // 将最小值顶点选中
		v0 = minIndex; // 下次查找从最限制顶点开始
	}
}
// C语言实现
void Dijkstra_c(int out[], int N, int v0){
	int i, j;
	int visited[maxN] = { 0 }; // 表示顶点是否被选中,0:顶点未被选中;1:顶点已被选中
	int last_visited = 0;
	for (i = 0; i < N; ++i){
		out[i] = INF; // 把输出结果全部初始化为无穷大
	}
	visited[v0] = 1; // 选中起始顶点
	out[v0] = 0;

	for (i = 0; i < N - 1; ++i) { // N 个顶点需要做 N - 1 次循环
		// 查看顶点周围的所有点
		for (j = 0; j < N; ++j) { // 循环遍历所有顶点
			if (visited[j] == 0) { // 保证被查看的新顶点没有被访问到
				if (matrix[v0][j] != 0){ // 保证当前顶点(V0)与新顶点(j)之间有路径
					int dist = matrix[v0][j] + last_visited; // 计算 V0 到 J 的路径距离
					if (dist < out[j])out[j] = dist; // 用新路径代替原来的路径
				}
			}
		}
		// 找出最小值
		int minIndex = 0;
		while (visited[minIndex] == 1) minIndex++; // 找第一个没有被选中的节点
		for (j = minIndex; j < N; ++j) {
			if (visited[j] == 0 && out[j] < out[minIndex]){
				minIndex = j;
			}
		}

		last_visited = out[minIndex]; // 更新最小值
		visited[minIndex] = 1; // 将最小值顶点选中
		v0 = minIndex; // 下次查找从最限制顶点开始
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
#if 0
	freopen("Dijkstra2Data.txt", "r", stdin);
	int result[maxN];
	int N, i, j;
	scanf("%d", &N);
	for (i = 0; i < N; ++i){
		for (j = 0; j < N; ++j){
			scanf("%d", &matrix[i][j]);
		}
	}

	Dijkstra_c(result, N, 0);

	for (i = 0; i < N; ++i){
		if (result[i] == INF)printf("INF\n");
		else printf("%d\n", result[i]);
	}
#endif

	freopen("Dijkstra2Data.txt", "r", stdin);
	int n;
	scanf("%d", &n);
	vector> vec(n, vector(n, 0));
	for (int i = 0; i < n; ++i){
		for (int j = 0; j < n; ++j){
			cin >> vec[i][j];
		}
	}

	vector result(n, INF); // 把输出结果全部初始化为无穷大
	Dijkstra_cpp(vec,result, 0);

	for (int i = 0; i < n; ++i){
		if (result[i] == INF)printf("INF\n");
		else printf("%d\n", result[i]);
	}
	return 0;
}


假设我们的测试用例如下图所示:

Dijkstra 算法的 C/C++ 实现_第1张图片

我们以A作为起始顶点,计算A到每个顶点的最短路径,注意,这是一幅带权图,图的邻接矩阵表示如下:

Dijkstra 算法的 C/C++ 实现_第2张图片

计算结果如下:

Dijkstra 算法的 C/C++ 实现_第3张图片

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