图|最短路径——迪杰斯特拉(Dijkstra)弗洛伊德(Floyd)

最短路径——迪杰斯特拉(Dijkstra)弗洛伊德(Floyd)

一、迪杰斯特拉算法(Dijkstra)

1. 问题:

求从每个源点到其余各顶点的最短路径。

2.存储结构:

1)图的存储结构: 带权的邻接矩阵
2)辅助数组:
一维数组dist:dist[ i ]表示当前求出的从源点到顶点 i 的路径长度,其初始状态为邻接矩阵第 i 行的值;
二维数组path:二维数组第 i 行path[ i ]表示源点到 i 的路径中经过的顶点下标集合,其初始值为 -1 。
3)算法实现:

void dijkstra(MGraph G, int v) {
    int dist[MAXSIZE];              //dist[i]:源点到点 i 的路径长度
    int path[MAXSIZE][MAXSIZE];     //path[i][]:源点到点 i 经过的顶点j下标集合
    int i, j, k, m, min, n, flag;
    
    for(i=0; i<G.vexNum; i++) {         //path[][]初始化为-1
        for(j=0; j<G.vexNum; j++) {
            path[i][j] = -1;
        }
    }
    
    for(i=0; i<G.vexNum; i++) {
        dist[i]=G.arcs[v][i];                //dist[]初始状态为arcs[][]第v行
        if(dist[i]!=0 && dist[i]!=INFINITY) {//与源点 v 有关系的顶点第一个经过的点为 v
            path[i][0]=v;
        }
    }
    n=0;        //打印最短路径时对应第%d条
    flag=1;     //循环结束标志
    
    //从小到大找最短路径
    while(flag) {
        k=0;                //每一轮循环中要选择的最短路径长度对应的顶点下标
        min=INFINITY;       //每一轮循环中要选择的最短路径长度
        
        for(j=0; j<G.vexNum; j++) {                      //找dist最小值
            if(dist[j]!=0 && dist[j]<min) {
                k=j;
                min=dist[j];
            }
        }
        printf("第%d条最短路径长度为%d--(", ++n, min);     //显示最短路径
        for(j=0; j<G.vexNum; j++) {
            if(path[k][j]!=-1) {                         //打印从源点到最短路径顶点经过的顶点
                printf("%d,", path[k][j]);
            }
        }
        printf("%d)\n", k);
        for(j=0; j<G.vexNum; j++) {                      //更新dist和path
            if(j!=k && G.arcs[k][j]!=INFINITY) {
                if(dist[k]+G.arcs[k][j]<dist[j]) {       //用更短的路径长度替换原来的dist
                    dist[j]=dist[k]+G.arcs[k][j];
                    for(m=0; m<G.vexNum; m++) {          //将path[k]复制到path[j]中
                        path[j][m]=path[k][m];
                    }
                    m=0;
                    while(m<G.vexNum && path[j][m]!=-1) {//找path[j]中最后一个数据的下标,即第1个-1的下标
                        m++;
                    }
                    path[j][m]=k;                        //将下标j加到path[j]的尾部
                }//if
            }//if
        }//for
        dist[k]=0;                                       //标志该顶点已输出
        flag=0;                                          //判断路径是否求完,若flag=1继续求,否则结束
        for(j=0; j<G.vexNum; j++) {
            if(dist[j]!=0 && dist[j]<INFINITY) {
                flag = 1;
            }
        }//for
    }//while
    
    for(i=0; i<G.vexNum; i++) {
        if(dist[i]==INFINITY) {
            printf("由%d作为源点%d顶点无法到达\n", v, i);
        }
    }
}

二、弗洛伊德算法(Floyd)

1. 问题:

求每一对顶点间的最短路径

2.存储结构:

1)图的存储结构: 带权的邻接矩阵
2)辅助数组:
二维数组d:d[ i ][ j ]表示当前求出的从 i 到 j 的路径长度;
二维数组path:每个二维数组元素path[ i ][ j ]是一个一维整形数组,存放当前 i 到 j 的路径做经过的顶点下标集合。
3)算法实现:

void floyd(MGraph G) {
    int i, j, k, m, n, p;
    int d[MAXSIZE][MAXSIZE];
    PATHINT path[MAXSIZE][MAXSIZE];
    
    for (i=0; i<G.vexNum; i++) {        //初始化数组 d 和 path
        for(j=0; j<G.vexNum; j++) {
            d[i][j] = G.arcs[i][j];
            for (k=0; k<MAXSIZE; k++) {
                path[i][j][k] = -1;
            }
        }
    }//for
    
    printf("\ndist的初值\n");
    for (i=0; i<G.vexNum; i++) {
        for (j=0; j<G.vexNum; j++) {
            printf("%6d", d[i][j]);
            printf("\t");
        }
        printf("\n");
    }
    
    for (i=0; i<G.vexNum; i++) {        //存放初始路径
        for (j=0; j<G.vexNum; j++) {
            if (d[i][j]!=INFINITY && d[i][j]!=0) {
                path[i][j][0] = i;
                path[i][j][1] = j;
            }
        }//for-j
    }//for-i
    
    printf("\npath的初值\n");
    for (i=0; i<G.vexNum; i++) {
        for (j=0; j<G.vexNum; j++) {
            for (k=0; path[i][j][k]!=-1; k++) {
                printf("%d,", path[i][j][k]);
            }//for-k
            printf("\t");
        }//for-j
        putchar('\n');
    }//for-i
    
    for (k=0; k<G.vexNum; k++) {            //用经过点 k 的路径更新上一次的路径
        for (i=0; i<G.vexNum; i++) {
            if (i==k) {
                continue;
            }
            for (j=0; j<G.vexNum; j++) {
                if (j==k) {
                    continue;
                }
                if (d[i][k]+d[k][j] < d[i][j]) {// d(k)[i][j] = min{ d(-1)[i][j], d(-1)[i][k] + d(-1)[k][j]) }
                    d[i][j] = d[i][k] + d[k][j];
                    //m,n两个for循环均为将经过k的更短的路径复制的过程
                    for (m=0; m<G.vexNum && path[i][k][m]!=-1; m++) {
                        path[i][j][m] = path[i][k][m];
                    }//for-m
                    for (n=0; n<G.vexNum && path[k][j][n]!=-1; n++) {
                        if (n>1) {
                            m++;
                        }
                        path[i][j][m] = path[k][j][n];
                    }//for-n
                }//if
            }//for-j
        }//for-i
        printf("\ndist的第%d次迭代结果\n", k+1);
        for(m=0; m<G.vexNum; m++) {
            for (n=0; n<G.vexNum; n++) {
                printf("%6d", d[m][n]);
            }//for-n
            putchar('\n');
        }//for-m
        
        printf("\npath的第%d次迭代结果\n", k+1);
        for (i=0; i<G.vexNum; i++) {
            for (j=0; j<G.vexNum; j++) {
                for (p=0;path[i][j][p]!=-1; p++) {
                    printf("%d,", path[i][j][p]);
                }//for-p
                printf("\t");
            }//for-j
            putchar('\n');
        }//for-i
    }//for-k
}//floyd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值