Dijkstra最优路径算法及具体C++实例实现

一、实现的最终效果

  1. 从键盘中输入有向图:首先输入有向图中总共的结点数与边数,然后再输入每一条边的信息,输入格式如下:From:起点,Weight:边的权重, To:终点。

Dijkstra最优路径算法及具体C++实例实现_第1张图片
2. 打印输入有向图的结果:以邻接矩阵的形式打印出矩阵结果。Dijkstra最优路径算法及具体C++实例实现_第2张图片
3. 求解最优路径:
Dijkstra最优路径算法及具体C++实例实现_第3张图片

二、Dijkstra算法原理

原理

Dijkstra算法是一种根据路径长度的递增顺序,逐步求出最短路径的算法,其主要思想为:首先求得一条最短的路径,然后再根据该条最短路径求得次最短路径,如此循环上述操作,最终求得一顶点至其他所有点的最短路径。如:

Dijkstra最优路径算法及具体C++实例实现_第4张图片
由上图可知,由源点v出发的最短路径为v-v1,此时就可确定已最短路径为v-v1有最短路径的基础上,从v1出发,看是否通过v1到其他点的路径,若新得到的路径比原本v到vn的路径短,则用v-v1-vn代替v-vn的路径,在此轮更新完毕后,选出路径中新得到的最小路径做为次最小路径,如此循环,即得到v到其他所有顶点的最短路径。

流程

有向图如图所示:
Dijkstra最优路径算法及具体C++实例实现_第5张图片
寻找A到其他各点最短路径的步骤如下:
进行第一轮地筛选:
Dijkstra最优路径算法及具体C++实例实现_第6张图片
得到最第一轮中的最短路径为A-B的路径,路径长度为1,在A-B的路径基础上进行第二轮筛选:
由上可知,由B出发可有的相邻结点有:B-C(长度为4)、B-D(长度为2)、B-E(长度为5),得到几条新的路径:A-B-C(长度为5)、A-B-D(长度为3)、A-B-E(长度为6),因为A-B-C比A-C短,A-B-D比A-D短,A-B-E比A-E长,所以更新A到C的路径,更新A到D的路径,最终得到的第二轮筛选结果如下所示。

Dijkstra最优路径算法及具体C++实例实现_第7张图片在第二轮筛选的结果中,最短路径为A-E,所以,通过A-E进行第三轮筛选:由E出发相邻的结点有:E-D(长度为3)(因为A-B已经是最短的路径,所以此处不用再算E到B的路径),得到的新路径为:A-E-D(长度为6),因A-E-D比A-D长,所以不用更新任何路径,结果如下。

Dijkstra最优路径算法及具体C++实例实现_第8张图片
由第三轮筛选结果得,A-B-D是最短的路径,所以在此基础上进行第四轮筛选:D无任何相邻结点,所以更新后结果如下。

Dijkstra最优路径算法及具体C++实例实现_第9张图片
至此,通过Dijkstra算法求出A到其它顶点的最优路径过程完毕,各最优路径分别为:
A到B:A-B,长度为1;
A到C: A-B-C,长度为5;
A到D: A-B-D, 长度为3;
A到E: A-E,长度为3。

三、代码实现

有向图的类代码

class GraphMatrix{
  public~GraphMatrix();

    void createdGraph();
    void printGraph();

    void inputVertexNumber(); //输入有向图的结点数目
    void makeVertexArray();//生成装有结点的数组
    void inputEdgeNumber();//输入有向图的边的数目
    void inputEdgeInfo();//输入边的信息,格式为:起点 权重 终点
    void addEdgeToList(int vFrom, int weight, int vTo);//添加边到对应的邻接矩阵中
    int n();//返回有向图的结点总数
    int e();//返回有向图的边的总数
    int first(int v);//返回结点v的第一个相邻结点 
    int next(int v, int w);//返回结点v在相邻结点w后的第一个邻结点
    int weight(int v1, int v2);//返回结点v1和v2之间的权重
    int getMark(int v);//得到结点v是否被访问的标记
    void setMark(int v, int val);//设置结点是否被访问的标记
    bool isEdge(int v1, int v2);//判断结点v1和v2间是否有边
    void setRoute(int v1, int v2, int val);//存储有向图的路径,将路径矩阵的坐标(v1, v2)处的值设为val(一般为结点值)。
    int getRoute(int i, int j);//得到存储路径的矩阵中结点i与j之间的值(一般为结点值)。
    int ConvertInput(string str);//将字符串str(地点名称)转换为对应的结点的数字 
    void CityName(int Node);//得到结点整数Node所对应的城市名称
    bool JudgeIsFalse(string str);//进行一些防错机制的判断
  
  private:
    int m_vCount;//结点数目
    int m_eCount;//边的数目
    int** m_vVertex;//邻接矩阵
    int *mark;//标记结点是否已确定最短路径
    int** Route;//存储具体的路径
    string *City;//存储城市的名称   
}; 

Dijkstra算法实现

Dijkstra最优路径算法及具体C++实例实现_第10张图片

  1. InitD()
    首先初始化源点至其它结点的只经过一条边的路径的长度,初始化后结果为:
名称 A B C D E
结点对应整数 0 1 2 3 4
D[] D[0] D[1] D[2] D[3] D[4]
0 1 7 3
void InitD(GraphMatrix * G, int * D, int StartNode){
    for (int i = 0; i < G->n(); i++){//从源点开始遍历每个结点
        if (G->isEdge(StartNode, i)){
            D[i] = G->weight(StartNode, i);//若源点StartNode与结点i之间存在边,则令D[i]等于两结点之间的权重
        }else{
            D[i] = INT_MAX;//若源点与结点i间不存在边,则令D[i]值为无穷大
        }
    }
    D[StartNode] = 0;//令源点与其本身的距离为0
}
  1. InitRouteMatrix()
    存储路径的矩阵是一个结点数目*结点数目的矩阵,矩阵中第i行为源点StartNode到第i个结点的路径,该行中第j个数值为该条路径经过的第j个结点。假设以A为源点,上图初始化后的路径矩阵为:
    A A -1 -1 -1
    A B -1 -1 -1
    A C -1 -1 -1
    A D -1 -1 -1
    A E -1 -1 -1
void InitRouteMatrix(GraphMatrix * G, int StartNode){
    for (int i = 0; i < G->n(); i++){//一层一层地对矩阵进行处理
        G->setRoute(i, 0, StartNode);//设置每层的第一个数为StartNode
        G->setRoute(i, 1, i);//设置每层的第二个数为层数
        for (int j = 2; j < G->n(); j++){
            G->setRoute(i, j, -1);//将每层的其余数值设为-1
        }
    }
}
  1. InitMark()
    将每个点设置为未被访问。
void InitMark(GraphMatrix* G){
    for (int i = 0; i < G->n(); i++){
        G->setMark(i, UNVISITED);//将每个点设置为未被访问
    }
}
  1. MinVertex()
    得到被用于下一次筛选的最短路径,最终会返回最短路径的终点。
int minVertex(GraphMatrix * G, int* D){
    int i, Shortest = 0;
    for (i = 0; i < G->n(); i++){
        if(G->getMark(i) == UNVISITED){
            Shortest = i;//先找到一个未被访问的结点
            break;
        }
    }
    for (i++; i < G->n(); i++){
        if ((G->getMark(i) == UNVISITED) && (D[i] < D[Shortest])){
            Shortest = i;//在其它未被标记的结点中找到一个具有更短路径的结点
        }
    }
    return Shortest;
} 
  1. Dijkstra()
void Dijkstra(GraphMatrix * G, int* Dis, int StartNode){
    int i, Shortest, w;
    InitD(G, Dis, StartNode);
    InitRouteMatrix(G, StartNode);//初始化路径矩阵
    InitMark(G);
    for (i = 0; i < G->n(); i++){
        Shortest = minVertex(G, Dis);//得到最短路径的终点
        if (Dis[Shortest] == INT_MAX) return;//若最短路径长度为正无穷,则此时剩余的路径中不存在可达的路径,则结束算法
        G->setMark(Shortest, VISITED);//将最短路径的终点设为已被访问
        for (w = G->first(Shortest); w < G->n(); w = G->next(Shortest, w)){//依次遍历最短路径终点的每个相邻结点
            if (Dis[w] > (Dis[Shortest] + G->weight(Shortest, w))){
                Dis[w] = Dis[Shortest] + G->weight(Shortest, w);//如果新得到的s与w间的路径长度D[v]+weight(v,w) < 原路径D[w], 则更新D[w]的值
                
                //更新路径矩阵
                //每当从s到w有更短的路径时,就将s到w的路径更新为s到v的路径 + v到w的边
                int j;
                for (j = 0; (G->getRoute(Shortest, j) != -1) && (j < G->n()); j++){
                    G->setRoute(w, j, G->getRoute(Shortest, j)); 
                }
                G->setRoute(w, j, w);
            }
        } 
    } 
}

源代码

若需要见源代码,请见:https://blog.csdn.net/qq_40369246/article/details/86651145

你可能感兴趣的:(最优路径)