概述
- 狄克斯特拉算法(
Dijkstra's Algorithm
)是一种用于计算单源最短路径的算法,适用于非负权重的有向图和无向图- 对于狄克斯特拉算法而言,图必须有权重才行
- 如果图是无权图(即所有边的权重都相同,可以视为权重为 1)
可以使用广度优先搜索(BFS
)来找到最短路径
因为BFS
会按层次遍历图,首先访问到的节点一定是最短路径
- 非负权重:
- 图中的所有边的权重(或成本)都必须是非负的,即权重不能是负数
- 狄克斯特拉算法无法处理负权重的边,因为负权重可能导致算法进入无限循环,从而无法正确计算最短路径
- 权重表示从一个节点到另一个节点的成本或距离
- 有向图:
- 图中的边有方向性,即从一个节点指向另一个节点
- 例如,从节点
A
到节点B
有一条边,但这条边并不意味着从B
到A
也有一条边
- 无向图:
- 图中的边没有方向性,即边连接的两个节点之间可以相互到达
- 例如,从节点
A
到节点B
有一条边,这意味着从B
到A
也有一条边,权重相同
主要思想
- 狄克斯特拉算法的主要思想是通过贪心策略逐步找到从起点到各个节点的最短路径
- 在每一步中,它选择当前距离最短的节点,然后更新其邻居节点的最短路径
步骤
- 初始化
- 设置起点到自己的距离为 0,其他节点到起点的距离为无穷大
- 使用一个优先队列(或最小堆)来存储节点及其当前已知的最短距离
- 将起点放入优先队列
- 迭代
- 从优先队列中取出距离最小的节点,记为当前节点
- 对于当前节点的每个邻居节点,计算从起点到该邻居节点的距离,如果该距离小于已知的最短距离,则更新该邻居节点的最短距离,并将其放入优先队列
- 重复上述过程,直到优先队列为空
场景
- 路径规划:
- 如地图导航中计算最短路径
- 网络路由:
- 在计算机网络中寻找从一个节点到另一个节点的最短路径
- 资源分配:
- 在任务调度中寻找最优资源分配路径
示例有权图
有权有向图
1 2 3 4 5 6 7 8 9 |
A /|\ 1 2 4 / | \ B C - D \ | / 2 1 3 \|/ E |
- 从节点
A
开始,计算到所有其他节点的最短路径 - 初始化:
distance[A] = 0
,distance[B] = ∞
,distance[C] = ∞
,distance[D] = ∞
,distance[E] = ∞
- 将
A
放入优先队列 - 取出
A
,更新其邻居:B
:distance[B] = 0 + 1 = 1
C
:distance[C] = 0 + 2 = 2
D
:distance[D] = 0 + 4 = 4
- 取出
B
,更新其邻居:E
:distance[E] = 1 + 2 = 3
- 取出
C
,更新其邻居:<code>E
:distance[E] = 2 + 1 = 3
(已经是最短距离,不更新)
- 取出
E
,更新其邻居:D
:distance[D] = 3 + 3 = 6
(已经是最短距离,不更新)
- 取出
D
,没有需要更新的邻居 - 最终最短路径为:
A -> B = 1
,A -> C = 2
,A -> D = 4
,A -> E = 3
有向图邻接表表示
- 假设有一个图,表示为邻接表:
1 2 3 4 5 6 7 8 9 |
A / \ 1 2 / \ B C \ / 4 3 \ / D |
- 邻接表表示为:
1 2 3 4 5 6 |
vector<vector<pair<int, int>>> graph = { {{1, 1}, {2, 2}}, // A -> B (weight 1), A -> C (weight 2) {{3, 4}}, // B -> D (weight 4) {{3, 3}}, // C -> D (weight 3) {} // D has no outgoing edges }; |
- 解释:
- 把
ABCD
分别标记为0123
graph
容器中,下标为0
的项,用来存A
相关的数据- 比如
{1,1}
表示,0
与1
之间的权重是1
,即A
和B
之间的权重是1
{2,2}
表示,0
与2
之间的权重是2
,即A
和C
之间的权重是2
- 把
有权无向图和邻接表
- 图
1 2 3 4 5 6 7 8 9 |
A / \ 1 2 / \ B C \ / 4 3 \ / D |
- 邻接表表示为:
1 2 3 4 5 6 |
vector<vector<pair<int, int>>> graph = { {{1, 1}, {2, 2}}, // A <-> B (weight 1), A <-> C (weight 2) {{0, 1}, {3, 4}}, // B <-> A (weight 1), B <-> D (weight 4) {{0, 2}, {3, 3}}, // C <-> A (weight 2), C <-> D (weight 3) {{1, 4}, {2, 3}} // D <-> B (weight 4), D <-> C (weight 3) }; |
示例代码
- 图
1 2 3 4 5 6 7 8 9 |
A /|\ 1 2 4 / | \ B C - D \ | / 2 1 3 \|/ E |
- 以下是一个使用优先队列(最小堆)实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#include <iostream> #include <vector> #include <queue> #include <utility> #include <limits> using namespace std; typedef pair<int, int> pii; vector<int> dijkstra(const vector<vector<pii>>& graph, int start) { int n = graph.size(); vector<int> distance(n, numeric_limits<int>::max()); priority_queue<pii, vector<pii>, greater<pii>> pq; distance[start] = 0; pq.push({0, start}); while (!pq.empty()) { int dist = pq.top().first; int node = pq.top().second; pq.pop(); if (dist > distance[node]) continue; for (auto& neighbor : graph[node]) { int nextNode = neighbor.first; int weight = neighbor.second; int newDist = dist + weight; if (newDist < distance[nextNode]) { distance[nextNode] = newDist; pq.push({newDist, nextNode}); } } } return distance; } int main() { int n = 5; // number of nodes vector<vector<pii>> graph(n); graph[0].push_back({1, 1}); // A -> B graph[0].push_back({2, 2}); // A -> C graph[0].push_back({3, 4}); // A -> D graph[1].push_back({4, 2}); // B -> E graph[2].push_back({4, 1}); // C -> E graph[4].push_back({3, 3}); // E -> D vector<int> distances = dijkstra(graph, 0); cout << "Shortest distances from node A:" << endl; for (int i = 0; i < distances.size(); ++i) { cout << "A -> " << char('A' + i) << " = " << distances[i] << endl; } return 0; } |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ 查找_顺序查找05/09
- ♥ 匹配_Rabin_karp匹配算法10/15
- ♥ 排序_堆排序05/08
- ♥ 排序_归并排序09/04
- ♥ 大话数据结构_图01/12
- ♥ 算法特点、哈希表06/29