大话数据结构学习笔记 - 图的最短路径之Dijkstra算法

大话数据结构学习笔记 - 图的最短路径之Dijkstra算法

最短路径

最短路径是图中的重要问题,对于网图非网图来说,最短路径的含义也是不同的。由于非网图没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径。而对于网图来说,最短路径,是指两顶点之间经过的边上的权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。当然非网图可以理解为所有边的权值都为1的网

迪杰斯塔拉(Dijkstra)算法

迪杰斯特拉(Dijkstra)算法是典型的最短路径算法,用于计算一个结点到其他结点的最短路径。算法的主要特点是以起始点为中心向外层层扩展(广度优先搜索思想), 直到扩展到终点为止

基本思想

通过Dijkstra计算图G中的最短路径时,需要指定起点v0, 即从v0点开始计算。 起初,设置S数组表示已求得最短路径的顶点, U数组表示起点到各顶点的最短距离, 即起点到各顶点最短路径的权值和。P数组表示最短路径中的各顶点

算法图解

大话数据结构学习笔记 - 图的最短路径之Dijkstra算法_第1张图片

以上图左图为例进行算法演示,右图为构建的无向图邻接矩阵。final数组为已求得最短路径的顶点集合,D数组为起点到各顶点的最短路径的权值和, P数组为最短路径的路径的顶点。

初始状态final数组表示起点v0到某顶点是否已求得最短路径的标记, 即若v0vw已有结果,则final[w]=1。起初final数组均为0D数组为{65535, 1, 5, 65535, 65535, 65535, 65535, 65535, 65535}

第一步 :将起始点v0加入到final数组, final[0] = 1, 此时final数组为{1, 0, 0, 0, 0, 0, 0, 0, 0}, 且v0v0路径为0. D数组为{0, 1, 5, 65535, 65535, 65535, 65535, 65535, 65535}

第二步: 寻找与final数组中已有顶点的最短距离, 并更新D数组。 与v0相连的顶点最短距离为v1顶点,权值为1, 故将v1加入到final数组。 final = {1,1,0,0,0,0,0,0,0,0}

第三步: 对更新后的final数组进行路径权值和的更新, 即D的更新 , 在原来的权值和基础上,更新新加入的顶点与其他各顶点得到权值和,比如final数组新增加v1顶点, 对D数组进行更新后, D = {0, 1, 4, 8, 6, 65535, 65535, 65535, 65535}

第四步: 寻找与final集合权值最短的顶点, 顶点v0、v1不参与, 故为顶点v2, 距离为4, 然后更新final数组和D数组 final = {1,1,1,0,0,0,0,0,0}D = {0,1,4,8,5,11,65535, 65535, 65535}, 此时P数组为P = {0,0,1,1,2,2,0,0,0}

循环依次继续, 最后final数组包含所有顶点, D数组包含起点到其余所有顶点的最短距离, P数组包含起点到任意顶点的路径长度。即迪杰斯塔拉算法解决了从某个源点到其余各顶点的最短路径问题

代码

无向图结构

#define MAXVEX 10
#define INF 65535
typdef int Patharc[MAXVEX];  // 用于存储最短路径下标的数组
typedef int ShortPathTable[MAXVEX];  // 用于存储起点到各点最短路径的权值和

typedef struct
{
    int vexs[MAXVEX];
    int arc[MAXVEX][MAXVEX];
    int numVertexes, numEdges;
}MGraph;

Dijkstra算法

/* Dijkstra算法, 求有向网 G 的 v0 顶点到其余顶点 v 最短路径 P[v] 及带权长度 D[v], P[v] 的值为前驱顶点下标,
 * D[v] 表示 v0 到 v 的最短路径长度和 */
void ShortestPath_Dijkstra(MGraph G, int v0, ShortPathTable *D, Patharc *P)
{
    int min, k, final[MAXVEX];  /* final[w] = 1 表示求得顶点 v0 至 vw 的最短路径 */
    for(int v = 0; v < G.numVertexes; v++)  /* 初始化数据 */
    {
        final[v] = 0;     /* 全部顶点初始化为未知最短路径状态 */
        (*D)[v] = G.arc[v0][v];   /* 将与 v0 顶点有连线的顶点加上权值 */
        (*P)[v] = -1;     /* 初始化路径数组 P 为 0 */
    }
    final[v0] = 1;   /* v0 至 v0 不需要求路径 */
    (*D)[v0] = 0;    /* v0 至 v0 路径为 0 */

    /* 开始主循环, 每次求得 v0 到某个 v 顶点的最短路径 */
    for(int v = 1; v < G.numVertexes; v++)
    {
        min = INF;   /* 当前所知离 v0 顶点的最近距离 */
        for(int w = 0; w < G.numVertexes; w++)   /* 寻找离 v0 最近的顶点 */
        {
            if(!final[w] && (*D)[w] < min)
            {
                min = (*D)[w];    /* w 顶点离 v0 顶点更近 */
                k = w;
            }
        }
        final[k] = 1;   /* 将目前找到的最近的顶点置为 1 */
        for(int w = 0; w < G.numVertexes; w++)   /* 更新当前最短路径及距离 */
        {
            /* 如果经过 v 顶点的路径比现在这条路径的长度短的话 */
            if(!final[w] && (min + G.arc[k][w]) < (*D)[w])
            {
                /* 说明找到了更短的路径, 修改 D[w] 和 P[w] */
                (*D)[w] = min + G.arc[k][w];   /* 修改当前路径长度 */
                (*P)[w] = k;
            }
        }
    }
}

算法源码

邻接矩阵最短路径之Dijkstra算法

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