暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

知识贴:最短路径Dijkstra算法

我们全都爱学习 2021-10-18
801

Dijkstra(迪杰斯特拉)算法是计算在有向图中从单原点到其他顶点的最短路径问题。



算法

基本思路是,按路径长度递增的顺序产生最短路径。


已知有向图定点集合(V[0], V[1], V[2], ..., V[n]),和边权值map[i][j]表示从顶点V[i]到顶点V[j]的长度(如果V[i]到V[j]能联通,则是边的直接权值,如果不能联通则是无穷大Inf),求从原点V[0]到其他节点的最短了路径。


步骤:

1. 把有向图的所有定点V分成两组:

  • S :表示已经求出最短路径的顶点集合。

  • T :表示尚未求出最短路径的顶点集合

  初始状态S为空,T为V-V[0]={V[1], V[2], V[3], ..., V[n]}。

2. 找出T中从V[0]开始最短路径最小的顶点(有说这是贪心算法),记为V[k]

  • 把V[k]从T中移出,然后加入到S中。

  • 然后对T中顶点的dist数组值进行修正。

    • 因为加入了新的中间节点V[k],判断经过新的中间节点V[k]之后,dist[i]值是否会比原来不经过这个中间节点V[k]小。

    • 即,dist[i] = min(dist[i],  dist[k]+map[k][i])

3. 重复2直到T为空为止。


算法理论依据:

从顶点V[0]到V[k]的最短路径,是下面两个值的较小者:

  • 是从V[0]到V[k]的直接路径的权值。

  • 是从V[0]经过S中顶点S[m],然后加上S[m]到V[k]的直接路径的权值。

    • 经过S中有顶点到达V[k]的路径有多条,取权值最小的一条。


算法缺点

  1. 边的权重不能是负数。

  2. 只能处理单原点的最短路径,也就是从固定一个点到其他顶点的最短路径,不能处理任意两个顶点的最短路径。

    1. 当然可以通过不停的调用Dijkstra算法,以期达到任意顶点之间的最短距离。

   


代码实现


下面给出一个c语言的算法实现;例子采用7个节点的一个有向图,如下:

实现中定义三个数组变量:

  1. distance[n]:用来存储从0节点到其他节点的最短路径。

    1. 如果一个节点已经处在S集合中,那么此时distance[i]就是从开始0节点到i节点的最短路径长度。

    2. 如果一个节点还是处在T集合中,那么此时distance[i]的值还不一定是最终的最短路径,可能是中间长度,在后续的计算调整中会逐步变成最短路径值。

  2. prepath[n]:表示从开始0节点到i节点的最短路径中,排在i节点前面的那个节点;这个数组用来输出打印路径中的节点序列使用。

  3. visited[n]:表示节点是否已经处理过了,如果等于true,那么节点已经放入S集合,即已经找出了最短路径,否则还在T集合里面。


#include <stdio.h>


void dijkstra(unsigned int map[][7], int n) {

    int distance[n];    the intermediate and final distance from node[0] to node[i]

    int prepath[n];     // the prefix node of node[i] in its path

    int visited[n];     // whethere node[i] has finished, i.e., found out the shortest path


    initialize

    for (int i = 1; i < n; i++) {

        distance[i] = map[0][i];

        prepath[i]  = 0;

        visited[i]  = 0;

    }

 

    // major loop

    for (int r = 1; r < n; r++) {

        unsigned min_dist = -1;

        int      min_idx  = -1;


        find out the minimun distance value from V set

        for (int i = 1; i < n; i++) {

            if (visited[i] == 0 && distance[i] <= min_dist) {

                min_dist = distance[i];

                min_idx = i;

            }

        }


       //printf("======== Round: %d ========\n", r);

      printf("distance S  : "); for (int i = 1; i < n; i++) { if (visited[i] != 0) printf("[%d]=%d ", i, distance[i]); } printf("\n");

      /printf("distance T  : "); for (int i = 1; i < n; i++) { if (visited[i] == 0) printf("[%d]=%d ", i, distance[i]); } printf("\n");

       //printf("pick min_idx: %d, min_dist: %d\n", min_idx, min_dist);


        // mark node[min_idx] as visited, i.e,. put to S set from T set

        visited[min_idx] = 1;


        // update distance value for V set node

        // for each node in V set, compare the path:

        //  distance[i] vs. distance[min_idx] + map[min_idx][i]

        for (int i = 1; i < n; i++) {

            if (visited[i] == 0 && map[min_idx][i] != -1 && min_dist + map[min_idx][i] < distance[i]) {

                distance[i] = min_dist + map[min_idx][i];

                prepath[i]  = min_idx;

            }

        }

    }

 

    // print final output, distance value and path

    for (int i = 1; i < n; i++) {

        printf("  distance[%d]: %d,\treverse path: %d", i, distance[i], i);


        int j = prepath[i];

        while (j != 0) {

            printf("<-%d", j);

            j = prepath[j];

        }

        printf("<-%d\n", 0);

    }

}


int main() {

    unsigned int map[][7] = {

        //      0   1   2   3   4   5   6

        //---+-------------------------

        /*0*/{  0, 13,  8, -1, 30, -1, 32},

        /*1*/{ -1,  0, -1, -1, -1,  9,  7},

        /*2*/{ -1, -1,  0,  5, -1, -1, -1},

        /*3*/{ -1, -1, -1,  0,  6, -1, -1},

        /*4*/{ -1, -1, -1, -1,  0,  2, -1},

        /*5*/{ -1, -1, -1, -1, -1,  0, 17},

        /*6*/{ -1, -1, -1, -1, -1, -1,  0},

        //-----------------------------

    };


    dijkstra(map, 7);

}


编译测试:

  distance[1]: 13, reverse path: 1<-0

  distance[2]: 8, reverse path: 2<-0

  distance[3]: 13, reverse path: 3<-2<-0

  distance[4]: 19, reverse path: 4<-3<-2<-0

  distance[5]: 21, reverse path: 5<-4<-3<-2<-0

  distance[6]: 20, reverse path: 6<-1<-0



文章转载自我们全都爱学习,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论