zoukankan      html  css  js  c++  java
  • 图->最短路径->单源最短路径(迪杰斯特拉算法Dijkstra)

     文字描述

      引言:如下图一个交通系统,从A城到B城,有些旅客可能关心途中中转次数最少的路线,有些旅客更关心的是节省交通费用,而对于司机,里程和速度则是更感兴趣的信息。上面这些问题,都可以转化为求图中,两顶点最短带权路径的问题。

      单源点的最短路径问题: 给定带权有向图G和源点v,求从v到G中其余各顶点的最短路径。迪杰斯特拉(Dijkstra)提出了一个按路径长度递增的次序产生最短路径的算法。迪杰斯特拉(Dijkstra)算法描述如下:

      

    示意图

      

      

       

    算法分析

      结合代码实现部分分析这个算法的运行时间。本博客写的代码,其时间复杂度为n^3, 但是理论上应该只为n^2

    代码实现

      1 //
      2 // Created by lady on 19-1-3.
      3 //
      4 #include <stdio.h>
      5 #include <stdlib.h>
      6 
      7 #define INFINITY        100000    //最大值
      8 #define MAX_VERTEX_NUM    20        //最大顶点数
      9 typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向网,无向图,无向网}
     10 typedef struct ArcCell{
     11     int weight;    //该弧相关信息的指针
     12 }ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM], PathMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM], ShortPathTable[MAX_VERTEX_NUM];
     13 typedef struct VertexType{
     14     char data[10];
     15 }VertexType;
     16 typedef struct{
     17     VertexType vexs[MAX_VERTEX_NUM];    //顶点向量
     18     AdjMatrix arcs;        //邻接矩阵
     19     int vexnum, arcnum;    //图的当前顶点数和弧数
     20     GraphKind kind;        //图的种类标志
     21 }MGraph;
     22 
     23 /*
     24  * 根据顶点信息, 返回该顶点在图中的位置, 如果返回-1表示顶点不存在
     25  */
     26 static int LocateVex(MGraph *G, char data[])
     27 {
     28     int i = 0;
     29     for(i=0; i<G->vexnum; i++){
     30         if(!strncmp(G->vexs[i].data, data, strlen(G->vexs[i].data))){
     31             return i;
     32         }
     33     }
     34     return -1;
     35 }
     36 
     37 /*
     38  * 用邻接矩阵作为存储结构,创建有向网
     39  */
     40 static int CreateGraphDN(MGraph *G)
     41 {
     42     printf("用邻接矩阵创建有向网,输入顶点数,弧数:");
     43     G->kind = DN;
     44     scanf("%d,%d", &G->vexnum, &G->arcnum);
     45     if(G->vexnum > MAX_VERTEX_NUM){
     46         printf("错误:顶点数不能超过%d!!
    ", MAX_VERTEX_NUM);
     47         return -1;
     48     }
     49     int i = 0, j = 0, k = 0;
     50     char v1[10] = {0}, v2[10]={0}, info[10] = {0};
     51     char tmp[30] = {0};
     52     for(i=0; i<G->vexnum; i++){
     53         printf("输入第%d个顶点: ", i);
     54         memset(G->vexs[i].data, 0, sizeof(G->vexs[0].data));
     55         scanf("%s", G->vexs[i].data);
     56         for(j=0; j<G->vexnum; j++){
     57             G->arcs[i][j].weight = INFINITY;
     58         }
     59         G->arcs[i][i].weight = 0;
     60     }
     61     for(k=0; k<G->arcnum; k++){
     62         printf("输入第%d条弧(顶点1, 顶点2): ", k);
     63         memset(tmp, 0, sizeof(tmp));
     64         scanf("%s", tmp);
     65         sscanf(tmp, "%[^','],%[^','],%s[^\n]", v1, v2, info);
     66         i = LocateVex(G, v1);
     67         j = LocateVex(G, v2);
     68         if(i<0 || j<0 || (!atoi(info))){
     69             printf("错误:顶点%s或者%s不存在, 或者权值信息%s不对!
    ", v1, v2, info);
     70             return -1;
     71         }
     72         G->arcs[i][j].weight = atoi(info);
     73     }
     74     return 0;
     75 }
     76 static void printMatrix(int vexnum, VertexType vexs[], int (*arcs)[MAX_VERTEX_NUM])
     77 {
     78     int i = 0, j = 0;
     79     printf("	");
     80     for(i=0; i<vexnum; i++){
     81         printf("%s	", vexs[i].data);
     82     }
     83     printf("
    ");
     84     for(i=0; i<vexnum; i++){
     85         printf("%s	", vexs[i].data);
     86         for(j=0; j<vexnum; j++){
     87             if(arcs[i][j] == INFINITY){
     88                 printf("INF	");
     89             }else{
     90                 printf("%d	", arcs[i][j]);
     91             }
     92         }
     93         printf("
    ");
     94     }
     95     return ;
     96 }
     97 
     98 static void printArchs(int vexnum, VertexType vexs[], AdjMatrix arcs)
     99 {
    100     int i = 0, j = 0;
    101     printf("	");
    102     for(i=0; i<vexnum; i++){
    103         printf("%s	", vexs[i].data);
    104     }
    105     printf("
    ");
    106     for(i=0; i<vexnum; i++){
    107         printf("%s	", vexs[i].data);
    108         for(j=0; j<vexnum; j++){
    109             if(arcs[i][j].weight == INFINITY){
    110                 printf("INF	");
    111             }else{
    112                 printf("%d	", arcs[i][j].weight);
    113             }
    114         }
    115         printf("
    ");
    116     }
    117     return ;
    118 }
    119 
    120 #include <string.h>
    121 /*
    122  * Dijkstra迪杰斯特拉算法
    123  * 从有向网G的顶点v0出发,求v0到其余顶点v的最短路径P[v]及其带权长度D[v].weight
    124  * 若P[v][w].weight为TRUE(1),则w是从v0到v当前求得最短路径上的顶点。
    125  * final[v]为TRUE(1),当且仅当v属于S,即已经求得从v0到v的最短路径
    126  */
    127 void ShortestPath_DIJ(MGraph *G, int v0)
    128 {
    129     int v = 0;
    130     int w = 0;
    131     int i = 0;
    132     int j = 0;
    133     int final[MAX_VERTEX_NUM] = {0};
    134     int min = 0;
    135     int P[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    136     ShortPathTable D;
    137 
    138     for(v=0; v<G->vexnum; ++v){
    139         D[v].weight = G->arcs[v0][v].weight;
    140         //设为空路径
    141         for(w=0; w<G->vexnum; ++w){
    142             P[v][w] = 0;
    143         }
    144         if(D[v].weight < INFINITY){
    145             P[v][v0] = 1;
    146             P[v][v] = 1;
    147         }
    148     }
    149     //初始化,v0顶点属于S集
    150     D[v0].weight = 0;
    151     final[v0] = 1;
    152     //开始主循环,每次求得v0到某个v顶点的最短路径,并加v到s集
    153     //其余G->vexnum-1个顶点
    154     for(i=1; i<G->vexnum; ++i){
    155         //min存放当前离v0顶点最短的距离
    156         min = INFINITY;
    157         for(w=0; w<G->vexnum; w++){
    158             if(!final[w]){
    159                 //顶点w在V-S中
    160                 if(D[w].weight < min){
    161                     //顶点v0更近
    162                     min = D[w].weight;
    163                     v = w;
    164                 }
    165             }
    166         }
    167         if(min == INFINITY)
    168             break;
    169         //离v0最短的顶点v加入S集合
    170         final[v] = 1;
    171         //更新当前最短路径和距离
    172         for (w = 0; w < G->vexnum; w++) {
    173             if (!final[w] && (min + G->arcs[v][w].weight < D[w].weight)) {
    174                 //修改D[w]和P[w],w属于V-S
    175                 D[w].weight = min + G->arcs[v][w].weight;
    176                 for(j=0; j<G->vexnum; j++){
    177                     P[w][j] = P[v][j];
    178                 }
    179                 P[w][w] = 1;
    180             }
    181         }
    182     }
    183 
    184     printf("
    打印最短路径:
    ");
    185     printMatrix(G->vexnum, G->vexs, P);
    186 
    187     printf("
    打印%s到其余顶点的带权长度:
    ", G->vexs[v0].data);
    188     for(i=0; i<G->vexnum; i++){
    189         if(D[i].weight == INFINITY){
    190             printf("%s,INF	", G->vexs[i].data);
    191         }else {
    192             printf("%s,%d	", G->vexs[i].data, D[i].weight);
    193         }
    194     }
    195     printf("
    ");
    196     return ;
    197 }
    198 
    199 int main(int argc, char *argv[])
    200 {
    201     //以邻接矩阵为存储结构创建有向网
    202     MGraph G;
    203     if(CreateGraphDN(&G) < 0){
    204         return -1;
    205     }
    206     printf("
    打印该图中的信息:
    ");
    207     printArchs(G.vexnum, G.vexs, G.arcs);
    208     //Dijkstra迪杰斯特拉算法求单源最短路径
    209     ShortestPath_DIJ(&G, 0);
    210     return 0;
    211 }
    单源最短路径(Dijkstra)

    代码运行

    /home/lady/CLionProjects/untitled/cmake-build-debug/untitled
    用邻接矩阵创建有向网,输入顶点数,弧数:6,8
    输入第0个顶点: v0
    输入第1个顶点: v1
    输入第2个顶点: v2
    输入第3个顶点: v3
    输入第4个顶点: v4
    输入第5个顶点: v5
    输入第0条弧(顶点1, 顶点2): v0,v5,100
    输入第1条弧(顶点1, 顶点2): v0,v4,30
    输入第2条弧(顶点1, 顶点2): v0,v2,10
    输入第3条弧(顶点1, 顶点2): v1,v2,5
    输入第4条弧(顶点1, 顶点2): v2,v3,50
    输入第5条弧(顶点1, 顶点2): v4,v5,60
    输入第6条弧(顶点1, 顶点2): v4,v3,20
    输入第7条弧(顶点1, 顶点2): v3,v5,10
    
    打印该图中的信息:
        v0    v1    v2    v3    v4    v5    
    v0    0    INF    10    INF    30    100    
    v1    INF    0    5    INF    INF    INF    
    v2    INF    INF    0    50    INF    INF    
    v3    INF    INF    INF    0    INF    10    
    v4    INF    INF    INF    20    0    60    
    v5    INF    INF    INF    INF    INF    0    
    
    打印最短路径:
        v0    v1    v2    v3    v4    v5    
    v0    1    0    0    0    0    0    
    v1    0    0    0    0    0    0    
    v2    1    0    1    0    0    0    
    v3    1    0    0    1    1    0    
    v4    1    0    0    0    1    0    
    v5    1    0    0    1    1    1    
    
    打印v0到其余顶点的带权长度:
    v0,0    v1,INF    v2,10    v3,50    v4,30    v5,60    
    
    Process finished with exit code 0
  • 相关阅读:
    Jmeter — 服务端监控工具:nmon
    JMeter — 使用ServerAgent 监控服务器资源
    Jmeter — 跨线程组传递参数
    Jmeter — 使用jp@gc
    Jmeter — 使用 jp@gc-Stepping Thread Group插件来设置负载场景
    Jmeter-使用jdbc发送sql & 配置JDBC Connection Configuration & JDBC Request的使用
    Jmeter-安装JSON Path Extractor插件
    Jmeter-环境搭建
    jdk-安装与环境变量配置
    收藏的一些关于测试的网址
  • 原文地址:https://www.cnblogs.com/aimmiao/p/10221669.html
Copyright © 2011-2022 走看看