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

来源:互联网 发布:tk域名注册不了 编辑:程序博客网 时间:2024/06/06 11:49

基本思想

迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于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;}
0 0