当前位置:   article > 正文

算法 - 图论Dijkstra(原理、思路代码实现、以东南大学真题为例讲解手算方法)_迪杰斯特拉算法 未访问节点

迪杰斯特拉算法 未访问节点

Dijkstra

算法原理
Dijkstra算法是一种经典的用于计算单源最短路径的算法。它可以在带权重的图中找到从源节点到所有其他节点的最短路径。Dijkstra算法通过贪心策略,不断选择当前已知最短路径最小的节点,更新其邻接节点的路径长度,直到处理完所有节点。

适用场景

  • 图中的边权重为非负值。
  • 需要计算从单一源点到其他所有节点的最短路径。

算法步骤

  1. 初始化:设定源节点的距离为0,其他所有节点的距离为无穷大。将所有节点标记为未访问状态。
  2. 从未访问节点中选择距离最小的节点作为当前节点。
  3. 对于当前节点的每一个未访问的邻接节点,计算从源节点经过当前节点到达该邻接节点的距离。如果该距离小于之前记录的距离,则更新该距离。
  4. 标记当前节点为已访问状态。
  5. 重复步骤2-4,直到所有节点都被访问过。

实现步骤

  1. 使用一个数组或字典记录每个节点的当前最短路径。
  2. 使用一个优先队列(最小堆)加速获取当前最短路径最小的节点。
  3. 不断从优先队列中取出最短路径最小的节点,更新其邻接节点的路径长度。
  4. 直到优先队列为空,所有节点的最短路径均已确定。

伪代码

function Dijkstra(Graph, source):
    dist[source] = 0
    create priority queue Q
    for each vertex v in Graph:
        if v ≠ source:
            dist[v] = infinity
            prev[v] = undefined
        Q.add_with_priority(v, dist[v])

    while Q is not empty:
        u = Q.extract_min()
        for each neighbor v of u:
            alt = dist[u] + length(u, v)
            if alt < dist[v]:
                dist[v] = alt
                prev[v] = u
                Q.decrease_priority(v, alt)

    return dist, prev
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

C语言代码

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

#define V 9  // 图中的顶点数

// 寻找当前未访问节点中距离最小的节点
int minDistance(int dist[], int sptSet[]) {
    int min = INT_MAX, min_index;
    for (int v = 0; v < V; v++) {
        if (sptSet[v] == 0 && dist[v] <= min) {
            min = dist[v], min_index = v;
        }
    }
    return min_index;
}

// 打印从源节点到所有其他节点的最短路径
void printSolution(int dist[]) {
    printf("Vertex \t Distance from Source\n");
    for (int i = 0; i < V; i++) {
        printf("%d \t\t %d\n", i, dist[i]);
    }
}

// 实现Dijkstra算法
void dijkstra(int graph[V][V], int src) {
    int dist[V];  // 存储源节点到其他节点的最短距离
    int sptSet[V];  // 标记节点是否已被处理

    // 初始化所有节点的最短距离为无穷大,sptSet为未访问状态
    for (int i = 0; i < V; i++) {
        dist[i] = INT_MAX, sptSet[i] = 0;
    }
    dist[src] = 0;

    // 遍历所有节点
    for (int count = 0; count < V - 1; count++) {
        int u = minDistance(dist, sptSet);
        sptSet[u] = 1;

        // 更新节点的最短路径
        for (int v = 0; v < V; v++) {
            if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
                dist[v] = dist[u] + graph[u][v];
            }
        }
    }
    printSolution(dist);
}

int main() {
    int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},
                       {4, 0, 8, 0, 0, 0, 0, 11, 0},
                       {0, 8, 0, 7, 0, 4, 0, 0, 2},
                       {0, 0, 7, 0, 9, 14, 0, 0, 0},
                       {0, 0, 0, 9, 0, 10, 0, 0, 0},
                       {0, 0, 4, 14, 10, 0, 2, 0, 0},
                       {0, 0, 0, 0, 0, 2, 0, 1, 6},
                       {8, 11, 0, 0, 0, 0, 1, 0, 7},
                       {0, 0, 2, 0, 0, 0, 6, 7, 0}};
    dijkstra(graph, 0);
    return 0;
}
  • 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
  • 60
  • 61
  • 62
  • 63
  • 64

代码解释

  • int minDistance(int dist[], int sptSet[]):找到未访问节点中距离最小的节点。
  • void printSolution(int dist[]):打印从源节点到所有其他节点的最短路径。
  • void dijkstra(int graph[V][V], int src):实现Dijkstra算法,从源节点计算到所有其他节点的最短路径。
  • int main():主函数,定义图的邻接矩阵并调用Dijkstra算法计算最短路径。

算法特点

  • 时间复杂度:O(V^2)(使用数组实现优先队列时),使用二叉堆可以优化到O((V + E) log V)。
  • 适用于图中的边权重为非负值的情况。
  • 通过贪心策略逐步找到从源节点到其他节点的最短路径。

通过上述代码和解释,读者应该可以理解Dijkstra算法的原理和实现步骤,并在实际应用中使用该算法计算最短路径。对于考研初试,只需掌握手算方法,我们以东南大学2000年真题为例进行讲解:
在这里插入图片描述

初始状态:

节点距离前驱
a0-
b-
c-
d-
e-
f-
g-

Round 1:

选择距离最小的节点a,更新其邻接节点的距离。

  • 更新节点c的距离为2(0 + 2),前驱为a。
  • 更新节点d的距离为12(0 + 12),前驱为a。
  • 更新节点b的距离为15(0 + 15),前驱为a。
节点距离前驱
a0-
b15a
c2a
d12a
e-
f-
g-

Round 2:

选择距离最小的节点c,更新其邻接节点的距离。

  • 更新节点e的距离为10(2 + 8),前驱为c。
  • 更新节点f的距离为6(2 + 4),前驱为c。
节点距离前驱
a0-
b15a
c2a
d12a
e10c
f6c
g-

Round 3:

选择距离最小的节点f,更新其邻接节点的距离。

  • 更新节点d的距离为11(6 + 5),前驱为f。
  • 更新节点g的距离为16(6 + 10),前驱为f。
节点距离前驱
a0-
b15a
c2a
d11f
e10c
f6c
g16f

Round 4:

选择距离最小的节点e,更新其邻接节点的距离。

  • 节点e没有需要更新的邻接节点。
节点距离前驱
a0-
b15a
c2a
d11f
e10c
f6c
g16f

Round 5:

选择距离最小的节点d,更新其邻接节点的距离。

  • 更新节点g的距离为13(11 + 2),前驱为d。
节点距离前驱
a0-
b15a
c2a
d11f
e10c
f6c
g13d

Round 6:

选择距离最小的节点g,更新其邻接节点的距离。

  • 节点g没有需要更新的邻接节点。
节点距离前驱
a0-
b15a
c2a
d11f
e10c
f6c
g13d

Round 7:

选择距离最小的节点b,更新其邻接节点的距离。

  • 节点b没有需要更新的邻接节点。
节点距离前驱
a0-
b15a
c2a
d11f
e10c
f6c
g13d

最终结果如下:

最短路径结果:

  • a -> a: 0
  • a -> b: 15 (路径:a-b)
  • a -> c: 2 (路径:a-c)
  • a -> d: 11 (路径:a-c-f-d)
  • a -> e: 10 (路径:a-c-e)
  • a -> f: 6 (路径:a-c-f)
  • a -> g: 13 (路径:a-c-f-d-g)
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/正经夜光杯/article/detail/956903
推荐阅读
相关标签
  

闽ICP备14008679号