经典算法——迪杰斯特拉(Dijkstra)最短路径

基本思想

迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

其基本思想是,设置顶点集合S并不断地作贪心选择来扩充这个集合。一个顶点属于集合S当且仅当从源到该顶点的最短路径长度已知。

初始时,S中仅含有源。设u是G的某一个顶点,把从源到u且中间只经过S中顶点的路称为从源到u的特殊路径,并用数组dist记录当前每个顶点所对应的最短特殊路径长度。Dijkstra算法每次从V-S中取出具有最短特殊路长度的顶点u,将u添加到S中,同时更新数组dist(算导中称作Relax)。一旦S包含了所有V中顶点,dist就记录了从源到所有其它顶点之间的最短路径长度。

伪代码

Dijkstra(G,w,s)
1. Initializ_single_source(G,s) //dist[] = INF, dist[s] = 0
2. S = 空集
3. Q=G.V
4. while Q != 空集
u = Extract-Min(Q)
S = SU{u}
for each vertex v属于G.adj[u]
Relax(u,v,w)

C++实现

#include<iostream>
#include<vector>
#include<stack>
//#include<limits.h>
using namespace std;

struct edge{
    int noEnd; //边的终点序号
    int w;  
    edge(int _no, int _w):noEnd(_no),w(_w){}
};

class Graph{
private:
    vector<vector<edge>> Edge; //邻接表
    vector<int> dist;
    vector<char> vertex; // 顶点信息
    int n; // 顶点个数
    int e; //边数
    vector<int> path; //记录着从源点v0到当前点最短路径的前驱节点序号
public:
    Graph(int _n, int _e):n(_n),e(_e){
        vertex.resize(n+1);  //计数序号从1开始
        Edge.resize(n+1);
        path.resize(n+1);
        dist.resize(n+1);
        //初始化
        for(int i=1; i<=n; i++){
            path[i] = -1;
            dist[i] = INT_MAX;
        }
    }

    //依次读入顶点信息
    void readVertex(){
        cout<<"请依次输入顶点信息:"<<endl;
        for(int i=1; i<=n; i++) cin>>vertex[i];
    }

    //依次读入边信息
    void readEdge(){
        cout<<"请依次输入边信息source,dst,weight:"<<endl;
        int r,d,w; //r、d、w分别表示起点、终点、权重
        for(int i=1; i<=e; i++){
            cin>>r>>d>>w;
            Edge[r].push_back(edge(d,w));
            // Edge[d].push_back(edge(r,w)) 无向图
        }
    }
    void Dijkstra(int v0);
    // v0是源点
    void printPath(int v, int v0){
        stack<int> s;       
        while(v != v0){
            s.push(v);
            v = path[v];
        }
        cout<<endl<<vertex[v0];
        while(!s.empty()){
            v = s.top();
            s.pop();
            cout<<"->"<<vertex[v];
        }
        cout<<endl;
    }
};

void Graph::Dijkstra(int v0){   
    dist[v0] = 0;
    vector<bool> isVisited(n+1,false);
    isVisited[v0] = true;
    for(int i=0; i<Edge[v0].size(); i++){
        edge tmp = Edge[v0][i];
        if(dist[v0] + tmp.w < dist[tmp.noEnd]){
             dist[tmp.noEnd] = dist[v0] + tmp.w;
             path[tmp.noEnd] = v0;
        }
    }
    int N=n-1;
    while(N--){

        //找到下一个加入S集合中的点
        int u = -1;
        int tmpMin = INT_MAX;
        for(int i=1; i<=n; i++){
            if(!isVisited[i] && dist[i] < tmpMin){
                u = i;
                tmpMin = dist[i];           
            }
        }
        isVisited[u] = true; 

        //Relax 更新dist
        for(int i=0; i<Edge[u].size(); i++){
            edge tmp = Edge[u][i];
            if(dist[u] + tmp.w < dist[tmp.noEnd]){
                 dist[tmp.noEnd] = dist[v0] + tmp.w;
                 path[tmp.noEnd] = u;
            }
        }
    }
}

int main(){
    int n,e;
    cout<<"请输入顶点数,边数:"<<endl;
    cin>>n>>e;
    Graph graph(n,e);

    graph.readVertex();
    graph.readEdge();

    int v0, v;
    cout<<"请输入源点及终点序号:"<<endl;
    cin>>v0>>v;
    graph.Dijkstra(v0);
    graph.printPath(v,v0);
    cout<<endl;
}
    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/hezhangping/article/details/52335413
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞