数据结构之图的最短路径

图的最短路径

迪杰斯特拉(Dijkstra)算法

  • 迪杰斯特拉算法是计算无向图或有向图的最短路径,而且是运用了深度遍历的方法来计算的。
  • 其中数组 Patharc[MAXVEX] 用来存储最短路径中每个顶点的下标
  • ShortPathTable[MAXVEX] 用来存放起始顶点到各顶点最短路径的权值和
  • Final[k] 用来标记顶点 k 存在于最短路径的顶点集中

进行简单的演示

  • 先来张无向图

在这里插入图片描述

  • 以 V0 为起点开始构建最短路径之旅,那么 V0 已经称为最短路径顶点中的一员,在 Final[0] = 1 之前,要初始化起始顶点到各顶点的最短路径的权值和。直接上图。

在这里插入图片描述

在这里插入图片描述

  • 首先遍历一遍存放最短路径的权值和的数组 ShortPathTable[] ,在其中找到最小的值及最小值对应的顶点,再以该顶点进行广度遍历,寻找到最短路径的延伸版

坐标变化如下

在这里插入图片描述

图形变化

在这里插入图片描述

找到最短路径为 V0 -> V1 -> V3 -> V2

  • 还是和上面一样先遍历在进行类似的广度遍历

坐标变化如下

在这里插入图片描述

图形变化
在这里插入图片描述

找到最短路径为 V0 -> V1 -> V3 -> V2 -> V4

  • So next like 上面一样先遍历在进行类似的广度遍历

坐标变化如下
在这里插入图片描述

图形变化

在这里插入图片描述

找到最短路径为 V0 -> V1 -> V3 -> V2 -> V4 -> V5

  • 经过上面的步骤,就找到了最短步骤,数组 ShortPathTable[] 是存放起始顶点到各顶点的最短路径,数组 Patharc[] 是存放的是顶点是能和此时数组的索引构成边的。

接下来就上代码了

void ShortestPath_DIjkstra(MGraph G, int v0, int P[], int D[])
{
    int k, Min;

    int Final[MAXVEX];          //标记动态顶点存在最短路径
    for (int v = 0; v < G.numVertexes; v++)   //初始化数据  initialization data
    {
        Final[v] = 0;               //初始化时标记各个顶点都未计入最短路径
        D[v] = G.arc[v0][v];        //将边的权值存入数组中
        P[v] = 0;                   //初始化路径数组都为0
    }

    D[v0] = 0;      //起始顶点v0标记为0也就是V0到V0的边
    Final[v0] = 1;  //此处标记的是V0到V0为权值,也就是无路径

    for (int v = 1; v < G.numVertexes; v++)
    {
        Min = INFINITY;         //标记最小值并初始化

        for (int w = 0; w < G.numVertexes; w++)
        {
            if (!Final[w] && D[w] < Min)
            {
                k = w;      //k表示找到了最短路径的另一个顶点
                Min = D[w];
            }
        }

        Final[k] = 1;           //标记该顶点已经纳入最短路径顶点群中一员

        for (int w = 0; w < G.numVertexes; w++)
        {
            if (!Final[w] && Min + G.arc[k][w] < D[w])
            {
                D[w] = Min + G.arc[k][w];
                P[w] = k;
            }
        }
    }
}


int mian{

	....
	
	//迪杰斯特拉(Dijkstra)算法
    int Patharc[MAXVEX];        //存放最短路径下标的数组
    int ShortPathTable[MAXVEX];     //存储到各点最短路径和
    int v0 = 0;                 //最短路径的起始顶点

    ShortestPath_DIjkstra(G, v0, Patharc, ShortPathTable);
    for (int i = 0; i < G.numVertexes; i++)
    {
        printf("%d ", ShortPathTable[i]);
    }

	.......
}

代码中创建图在,前面的记录中

该算法的时间复杂度是 O(n^2)

费罗伊德(Floyd)算法

Floyd 算法也是求最短路径,不过它更复杂一些,它将使用一位数组转向了使用二维数组,该算法使用了两个数组分别来存放顶点到顶点的最短路径权值和(代号A数组)以及顶点最小路径的中每个顶点的前驱前驱顶点(代号B数组)

先来分析下 A 数组,根据下图来分析;在无向图中,我们会先对 A 数组进行初始化,也就是将图用矩阵来存储,初始化的矩阵存放的都是相邻两顶点之间边的权值,无穷大表示不构成边;现在要存放 V0 -> V3 这条路径的权值,但是邻接矩阵里面存放的是 [V0][V1] [V1][V3] [V0][V2] [V2][V3] 这些边的权值,但是要 存放路径 [V0][V3] 的权值只能这样 [V0][V1] + [V1][V3] 或者 [V0][V2] + [V2][V3],我们发现构建这条路径的方法很多,但是我们要根据 MIN{ [v][w], [v][k] + [k][w]} 这样的公式将构建 [v0][v3] 的最短路径权值存放进 A数组,由于里面已经存放了有一个中间顶点的路径,在这基础上可以计算并存放存在多个中间顶点的路径的权值和。

在分析 A 数组的同时,B 数组也要分析,首先 B 数组初始化后里面都是存放的(从左向右看)能构成边的两个顶点的右边顶点,然而是两个以上的顶点的路径呢(对应的数组里面存放的是前驱顶点),比如上面的 [V0][V3] ,在 B 数组中该位置就要存放最短路径的中间顶点 V1 了;复杂一点如 [V0][V4] 呢,此时 B 数组里面的值已经变换,先打印其实点 V0, 再打印路径中的这些顶点 [V0][V4] -> [ [V0][V4] ][4] -> [ [ [V0][V4] ][4] ][4] , 原理就是这些路径的顶点都是间接存放在相应的数组的列中(比如[V0][V4]存放在第四列中),条件是根据起始顶点来打印。

在这里插入图片描述

代码

void ShortestPath_Floyd(MGraph G, int (*P)[MAXVEX], int (*D)[MAXVEX])
{
    int k;
    //初始化路径矩阵和权值矩阵
    for (int v = 0; v < G.numVertexes; v++)
    {
        for (int w = 0; w < G.numVertexes; w++)
        {
            P[v][w] = w;
            D[v][w] = G.arc[v][w];
        }
    }

    for (int k = 0; k < G.numVertexes; k++)
    {
        for (int v = 0; v < G.numVertexes; v++)
        {
            for (int w = 0; w < G.numVertexes; w++)
            {
                if (D[v][w] > D[v][k] + D[k][w])
                {
                    D[v][w] = D[v][k] + D[k][w];
                    D[w][v] = D[v][w];
                    P[v][w] = P[v][k];
                    P[w][v] = P[v][w];
                }
            }
        }
    }

    //求最短路径
    for (int v = 0; v < G.numVertexes; v++)
    {
        for (int w = v + 1; w < G.numVertexes; w++)
        {
            printf("顶点start:%c --- 顶点end:%c  weight:%d : ", G.vexs[v], G.vexs[w], D[v][w]);
            k = P[v][w];
            printf("The path is : %c", G.vexs[v]);
            while(k != w)
            {
                printf(" -> %c", G.vexs[k]);
                k = P[k][w];
            }
            printf(" -> %c\n", G.vexs[w]);
        }
        printf("\n");
    }
}


int main(){
	 //弗洛伊德(Floyd)算法
    int Pathmatrix[MAXVEX][MAXVEX];
    int ShortPathTable[MAXVEX][MAXVEX];

    ShortestPath_Floyd(G, Pathmatrix, ShortPathTable);

}

这个算法的复杂度就了,为 O(n^3)。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值