算法思想:
令G = (V,E)为一个带权有向图,
把图中的顶点集合V分成两组,第一组为已求出最短路径的顶点集合S(初始时S中只有源节点,以后每求得一条最短路径,就将它对应的顶点加入到集合S中,直到全部顶点都加入到S中
);第二组是未确定最短路径的顶点集合U。在加入过程中,总保持从源节点v到S中各顶点的最短路径长度不大于从源节点v到U中任何顶点的最短路径长度。
算法步骤:
(1)初始化时,S只含有源节点;
(2)从U中选取一个距离v最小的顶点k加入S中(该选定的距离就是v到k的最短路径长度 );
(3)以k为新考虑的中间点,修改U中各顶点的距离;若从源节点v到顶点u的距离(经过顶点k )比原来距离(不经过顶点k )短,则修改顶点u的距离值,修改后的距离值是顶点k的距离加上k到u的距离;
(4)重复步骤(2)和(3),直到所有顶点都包含在S中。
(2)从U中选取一个距离v最小的顶点k加入S中(该选定的距离就是v到k的最短路径长度 );
(3)以k为新考虑的中间点,修改U中各顶点的距离;若从源节点v到顶点u的距离(经过顶点k )比原来距离(不经过顶点k )短,则修改顶点u的距离值,修改后的距离值是顶点k的距离加上k到u的距离;
(4)重复步骤(2)和(3),直到所有顶点都包含在S中。
代码实例:
#include <iostream> #include <string> #include <sstream> using namespace std; struct Dis{ // 对于集合 V(G) 内每一个元素构建结构体 string path; // 路径 int value; // 权值 bool visit; Dis() { visit = false; value = 0; path = ""; } }; string to_string(int n) // int 类型转 string 类型 { ostringstream stream; stream << n; return stream.str(); } class Graph{ private: int vexnum; // 顶点数目 int edge; // 边数 int **arc; // 邻接矩阵 Dis *dis; public: Graph(int vexnum,int edge); //邻接矩阵法创建图 ~Graph(); bool check_edge_value(int start, int end, int weight); // 检查待插入元素位置是否正确 void createGraph(); // 向邻接矩阵中输入数据 void print(); // 打印图 void Dijkstra(int begin); // 最短路径算法 void print_path(int number); // 输出最短路径 }; Graph::Graph(int vexnum,int edge) { this->vexnum = vexnum; this->edge = edge; arc = new int *[this->vexnum]; dis = new Dis [this->vexnum]; for(int i = 0; i < this->vexnum; ++i) { arc[i] = new int[this->vexnum]; for(int k = 0; k < this->vexnum; ++k) arc[i][k] = INT_MAX; } } Graph::~Graph() { delete[] dis; for(int i = 0; i < vexnum; ++i) delete arc[i]; delete arc; } bool Graph::check_edge_value(int start, int end, int weight) { if(start < 1 || end < 1 || weight < 0 || start > vexnum || end > vexnum) return false; return true; } void Graph::createGraph() { cout << "input every points start end weight" << endl; int start,end,weight,count = 0; while(count != edge) { cin >> start >> end >> weight; while(!check_edge_value(start,end,count)) { cout << "input error,please again" << endl; cin >> start >> end >>weight; } arc[start-1][end-1] = weight; ++count; } } void Graph::print() { for(int i = 0; i < vexnum; ++i) { for(int j = 0; j < vexnum; ++j) { if(arc[i][j] == INT_MAX) cout << "∞ "; else cout << arc[i][j] << " "; } cout << endl; } } // 迪杰特斯拉算法 void Graph::Dijkstra(int begin) { for(int i = 0; i < vexnum; ++i) { dis[i].path = "v" + to_string(begin) + "-->v" + to_string(i + 1); dis[i].value = arc[begin-1][i]; } dis[begin-1].value = 0; dis[begin-1].visit = true; dis[begin-1].path = "v"+to_string(begin); for(int i = 0; i < vexnum; ++i) { int temp = 0; int min = INT_MAX; for(int j = 0; j < vexnum; ++j) //选取除最短顶点集合外的最短路径 { if(dis[j].visit == false && dis[j].value < min) { min = dis[j].value; temp = j; } } dis[temp].visit = true; for(int k = 0; k < vexnum; ++k) { if(dis[k].visit == false && arc[temp][k] != INT_MAX && dis[temp].value+arc[temp][k] < dis[k].value) // 算法核心:新加入的点是否能到达其他点,并且通过该点到达目标点的路径是否小于直接到达 { dis[k].value = dis[temp].value + arc[temp][k]; //更新路径 dis[k].path = dis[temp].path+"-->v"+to_string(k+1); //记录路径 } } } } void Graph::print_path(int number) { if(dis[number-1].value == INT_MAX) cout << "it can not reach" << endl; else cout << "path:" << dis[number-1].path; } int main(int argc,char **argv) { int start,end,vex,arc; cout << "input the number of vex and arc:"; cin >> vex >> arc; Graph g(vex,arc); g.createGraph(); g.print(); cout << "start:"; cin >>start; g.Dijkstra(start); cout << "end:"; cin >> end; g.print_path(end); return 0; }
参考文献:
[1].程杰.大话数据结构[M].清华大学出版社.2011