迪杰斯特拉算法(学习版)

来源:互联网 发布:抗韩中年人淘宝店网址 编辑:程序博客网 时间:2024/06/07 10:17

迪杰斯特拉算法:按路径长度递增的次序产生最短路径的算法。

问题描述:给定带权有向图G和原点v0,求从v0G其余各顶点的最短路径。

 

求解过程:

对于网N=VE),将N中顶点分成两组:

第一组S :已求出的最短路径的终点集合(初始时只包含源点v0

第二组V-S :尚未求出的最短路径的顶点集合(初始时为V-{v0})。

算法将按照各顶点与v0间最短路径长度递增的次序,逐个将集合V-S中的顶点加入到集合S中去。在这个过程中,总保持从v0到集合S中各顶点的路径长度始终不大于集合V-S中各顶点的路径长度。

算法是按路径长度递增的次序来产生最短路径的,故此长度比此路径短的所有路径已经产生,他们的终点必定在S中。

 

 

 

算法的实现:

假设用带权的邻接矩阵arcs来表示带权有向网GG.arcs[i][j]表示弧<vi,vj>上的权值。若<vi,vj>不存在,则置G.arcs[i][j]为无穷大,源点为v0

算法的实现要引入以下辅助的数据结构

1)一维数组S[i] : 记录从源点v0到终点vi是否已被确定最短路径长度,true表示确定,false表示未确定。

2)一维数组Path[i] : 记录从源点v0到终点vi的当前最短路径上vi的直接前驱顶点符号。

3)一维数组D[i] : 记录从源点到顶点vi的当前最短路径长度。其初值为:如果从v0vi有弧,则D[i]为弧上的权值,否则为无穷大。

 

显然,长度最短的一条最短路径必定为(v0vk),满足下列条件:

D[k]=Min{D[i]|viV-S}

求得顶点vk的最短路径后,将其加入到第一组顶点集合S中。

每当加入一个新的顶点到集合集S,对第二组剩余的各点而言,多了一个“中转站”,因此要对第二组剩余的各个顶点的最短路径长度进行更新。

 

原来v0vi的最短路径长度为D[i],加进vk之后,以vk作为中间顶点的”中转站”长度为:D[k]+G.arcs[k][i],D[k]+G.arcs[k][i]<D[i], 则用D[k]+G.arcs[k][i]代替D[i].

更新后,再选择数组D中值最小的顶点加入到第一组顶点集S中,如此进行下去,直到图中所有顶点都加入到第一组顶点集S中为止。

#pragma once#include<iostream>#include<cstring>using namespace std;struct Dis{string path;int value;bool visit;Dis(){visit = false;value = 0;path = " ";}};class Graph_DG{private:int vexnum;int edge;int **arc;Dis * dis;public://构造函数Graph_DG(int vexnum, int edge);//析构函数~Graph_DG();//判断我们每次输入的边的信息是否合法//顶点从1开始编号bool check_edge_value(int start, int end, int weight); //创建图void createGraph();//打印邻接矩阵void print();//求最短路径void Dijkstra(int begin);//打印最短路径void print_path(int); };#include"Dijkstra.h" //构造函数Graph_DG::Graph_DG(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_DG::~Graph_DG(){delete[]dis;for(int i=0; i<this->vexnum; i++){delete this->arc[i];}delete arc;} //判断我们每次输入的边的信息是否合法//顶点从1开始编号bool Graph_DG::check_edge_value(int start, int end, int weight){if(start<1||endl<1||start>vexnum||end>vexnum||weight<0){return false;}return true;} void Graph_DG::createGraph(){cout<<"请输入每条边的起点和终点(顶点编号从1开始)以及权重"<<endl;int start;int endl;int weight;int count = 0;while(count !=this->edge){cin>>start>>end>>weight;//首先判断边的信息是否合法while(!this->check_edge_value(start, endl, weight)) {cout<<"输入的边的信息不合法,请重新输入"<<endl;cin>>start>>end>>weight; }//对邻接矩阵对应上的点赋值arc[start - 1][end - 1] = weight;//无向图添加上这行代码//arc[end - 1][start - 1] = weight;++count; }}void Graph_DG::print(){cout<<"图的邻接矩阵为:"<<endl;int count_row = 0;//打印行的标签 int count_col = 0;//打印列的标签//开始打印while(count_row != this->vexnum){count_col = 0;while(count_col != this->vexnum){if(arc[count_row][count_col] = INT_MAX){cout<<" ∞"<<" ";}else{cout<< arc[count_row][count_col]<<" ";++count_col;}}cout<<endl;++count_row;} }void Graph_DG::Dijkstra(int begin){//首先初始化我们的dis数组int i;for(i = 0;i<this->vexnum; i++){//设置当前的路径dis[i].path = "v" + to_string(begin)+"->v"+to_string(i+1);dis[i].value = arc[begin-1][i]; } //设置起点到起点的路径为0;dis[begin - 1].value = 0;dis[begin - 1].visit = true;int count = 1;//计算剩余的顶点的最短路径(剩余this->vexnum-1个顶点)while(count != this->vexnum){//temp用于保存当前dis数组中最小的那个下标//min记录的当前的最小值int temp;int min = INT_MAX;for(i = 0; i<(this->vexnum); i++){if(!dis[i].visit&&dis[i].value<min){min = dis[i].value;temp = i;}} //cout<<temp + 1<<"  "<<min<<endl;//把temp对应的顶点加入到已经找到的最短路径的集合中dis[temp].visit = true;++count;for(i = 0;i<this->vexnum;i++){//注意这里的条件arc[temp][i]!+INT_MAX必须加,不然会出现溢出if(!dis[i].visit&&arc[temp][i]!=INT_MAX&&(dis[temp].value+arc[temp][i])<this[i].value){//如果新得到的边可以影响其他为访问的顶点,那就更新它的最短路径和长度dis[i],value = dis[temp] + arc[temp][i];dis[i].path = dis[temp].path+"->v"+to_string(i+1); } } } }void Graph_DG::print_path(int begin){string str;str = "v" + to_string(begin);cout<<"以"<<str<<"为起点的图的最短路径为:"<<endl;for(int i = 0;i!= this->vexnum; i++){if(dis[i].value!= INT_MAX){cout<<dis[i].path<<"="<<dis[i].value<<endl; }else {cout<<dis[i].path<<"是无最短路径的"<<endl;} }}#include"Dijkstra.h"//检验输入边数和顶点数的值是否有效//顶点数和边数的关系是:(Vexnum*(vexnum - 1)/2)<edgebool check(int Vexnum,int edge){if(Vexnum<=0 || edge<=0 ||((Vexnum*(vexnum - 1))/2)<edge){return false;}return true;} int main(){int vexnum ;int  edge;cout<<"输入图中顶点的个数和条数:"<<endl;cin>>vexnum>>edge;while(!=check(vexnum, edge)){cout<<"输入的数值不合法,请重新输入:"<<endl;cin>>vexnum>>edge; }Graph_DG graph(vexnum, edge);graph.createGraph();graph.print();graph.Dijkstra(1);graph.print_path(1);system("pause");return 0;}