迪杰斯特拉算法(C++)

目录

 

介绍:

代码: 

结果:

介绍:

迪杰斯特拉算法(Dijkstra's algorithm)是一种用于计算加权图的单点最短路径的算法。它是由荷兰计算机科学家Edsger W. Dijkstra在1956年发明的。

该算法的思路是,从给定源点开始,不断找到距离该点最近的未访问节点,标记这个节点为已访问,并更新与该节点相邻的节点的最短路径。通过这样不断扩大已访问节点的范围,最终可以求出源点到其他所有节点的最短路径。

具体实现时,可以使用一个优先队列来保存即将访问的节点,优先队列中的元素按照节点与源点的距离从小到大排序,每次取出距离最小的节点进行访问。

迪杰斯特拉算法的复杂度为O(E log V),其中E为边的数量,V为节点的数量。虽然该算法是一个贪心算法,并不能保证一定找到最优解,但对于大多数实际应用场景而言,其效率和正确性都已经得到了充分的验证。

 

代码: 

#include<iostream>
using namespace std;
int G[100][100], n, maxint=999, min1, v;
int s[100],d[100],path[100];//集合s代表已经找到最短路径的点
void DIJ(int v0)//迪杰斯特拉算法,从v0点到任意点的最短路径
{
	for (int i = 0; i < n; i++)//初始化
	{
		s[i] = 0;//视为空集
		d[i] = G[v0][i];//初始最短路径为v0到个点的权值
		if (d[i] < maxint)//v0与i之间有弧,则前驱设为v0
			path[i] = v0;
		else//v0与i之间无弧,则前驱设为-1
			path[i] = -1;
	}
	s[v0] = 1;//将v0加入集合s
	d[v0] = 0;//源点到源点距离为0
	for (int i = 1; i < n; i++)//访问剩下的n-1个点
	{
		min1 = maxint;
		for (int j = 0; j < n; j++)
		{
			if (!s[j] && d[j] < min1)//点不在集合s内且小于最小边
			{
				v = j;//选择一条当前最短路径,终点为v
				min1 = d[j];
			}
		}
		s[v] = 1;//将v加入集合s
		for (int j = 0; j < n; j++)//将v加入集合后,更新从v0到剩余点的最短路
		{
			if (!s[j] && (d[v] + G[v][j]) < d[j])//该点不在集合s内且加入v点后最短路径小于之前的最短路径
			{
				d[j] = d[v] + G[v][j];//更新最短路径
				path[j] = v;//前驱设为v
			}
		}
	}
	for (int i = 1; i < n; i++)//访问各点的最短路径
	{
		int t = path[i];
		cout << i << "点的最短路径:"<<i<<" ";
		while (t != -1)
		{
			cout << t << " ";
			t = path[t];
		}
		cout << "最短路径长度"<<d[i];
		cout << endl;
	}
}
int main()
{
	cout << "输入顶点数:" << endl;
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			 G[i][j] = maxint;
	cout << "输入边数:" << endl;
	int e;
	cin >> e;
	cout << "输入边:" << endl;
	for (int i = 1; i <= e; i++)
	{
		int v1, v2, w;
		cin >> v1 >> v2 >> w;
		G[v1][v2] = w;
	}
	DIJ(0);//从0号点到任意点的最短路径
}

结果:

迪杰斯特拉(Dijkstra) 算法是一种用于解决单源最短路径问题的经典图算法。它能够找出从一个特定的起始顶点到图中其他所有顶点之间的最短路径。该算法适用于非负权值的情况,并且常应用于网络路由、地图导航等领域。 ### C++ 实现基本步骤: #### 1. 定义结构体或类表示图的边和顶点 ```cpp struct Edge { int to; double weight; }; struct Vertex { std::vector<Edge> adjacents; // 邻接边列表 }; ``` #### 2. 初始化数据结构 通常需要一个 `std::map` 来记录每个顶点的距离以及是否已被访问的状态。假设我们有 `std::unordered_map<int, pair<double, bool>> distAndVisited`,其中 `int` 表示顶点编号,`pair<double, bool>` 包含当前已知的距离和是否已经被访问。 #### 3. 实现迪杰斯特拉算法的核心函数 ```cpp void dijkstra(std::unordered_map<int, pair<double, bool>>& distAndVisited, const std::vector<Vertex>& graph, int startVertex) { for (const auto& vertex : graph) { distAndVisited[vertex.id] = {std::numeric_limits<double>::max(), false}; // 初始设置距离无穷大,未访问 } distAndVisited[startVertex].first = 0.0; // 起始节点的距离设为0 while (!distAndVisited.empty()) { int currentVertex = -1; double minDistance = std::numeric_limits<double>::max(); // 找出下一个处理的节点,即待处理节点中未访问且距离最小的节点 for (const auto& it : distAndVisited) { if (!it.second.second && it.first != startVertex && it.second.first < minDistance) { minDistance = it.second.first; currentVertex = it.first; } } // 如果所有节点都被访问过,则结束循环 if (currentVertex == -1) break; // 标记当前节点为已访问 distAndVisited[currentVertex].second = true; for (const auto& edge : graph[currentVertex].adjacents) { int nextVertex = edge.to; double newDistance = distAndVisited[currentVertex].first + edge.weight; // 更新相邻节点的距离如果更小 if (newDistance < distAndVisited[nextVertex].first) { distAndVisited[nextVertex].first = newDistance; } } } } ``` #### 4. 使用示例 ```cpp #include <iostream> #include <vector> #include <unordered_map> #include <limits> // ... 以上定义的结构体和函数 ... int main() { // 构建图的实例,添加边和顶点信息 std::vector<Vertex> graph = {/* 添加顶点和边 */}; // 执行迪杰斯特拉算法 dijkstra(distAndVisited, graph, 0); // 假设起始点为0 // 输出结果,例如打印从起点到其他所有顶点的最短距离 for (const auto& vertex : distAndVisited) { std::cout << "Vertex " << vertex.first << ": Distance = " << vertex.second.first << std::endl; } return 0; } ``` ### 相关问题: 1. **迪杰斯特拉算法如何处理带负权重的图?** - 对于包含负权重边的图,迪杰斯特拉算法无法保证找到正确的解。在这种情况下,可以考虑使用贝尔曼-福特算法。 2. **为什么需要初始化所有顶点的距离为无穷大?** - 初始化为无穷大的目的是为了确保从起始节点开始计算距离,而初始状态下的距离未知。这有助于算法正确地计算并更新每个顶点的新距离。 3. **在实际应用中,迪杰斯特拉算法还有哪些限制?** - 主要是关于时间复杂度和内存消耗。在大规模图上运行可能会导致性能瓶颈,此外,算法本身并不适合实时系统或对响应时间有极高要求的应用场景。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值