C++代码,数据结构-最短路径(两种情况)(迪杰斯特拉算法和弗洛伊德算法)

来源:互联网 发布:锐思数据库 编辑:程序博客网 时间:2024/05/01 08:12

1.单源的,从有向图某个源点, 到其他点的最短路径

利用算法迪杰斯特拉算法;

Dijkstra算法的基本思想:

一个辅助数组D[max_v];每个D[i]表示当前所知源点到vi的最短路径的长度

一个辅助集合S,记录已找到最短路径的顶点的集合,他是逐步补充的;知道S集合包括所有点,起初S集合包含源点

1.先找出源点直接可达到顶点i,并把权记录到D[i]中,不可达到顶点记为最大值;

2.然后进行n-1次循环,把其他点一次找出最短路径;

每次循环先找出D中最小的值min,和v(D[v]=min); 把v加入到集合S中,

3.然后寻找不属于S集合的点w,如果min+dut(v-w的权值)<D[w],则更新D[w]的值,

4.重复2,和3,知道S集合包括所有点。

下面是代码,我自己又写了一个函数来呈现结果,

#include<iostream>#include<fstream>#define Max_v 200using namespace std;//算法7.15 最短路径struct Arccell{int adj;};typedef Arccell adjmatric[Max_v][Max_v];struct Mgraph{char vexs[Max_v];   //顶点向量adjmatric arcs;   //邻接矩阵int  vexnum,arcnum;  //顶点数 和 弧数};int locate(Mgraph G,char ch){for(int i=0;i!=G.vexnum;++i){    if(G.vexs[i]==ch)return i;}}void createDG(Mgraph &G){//采用数组表示法,构造有向图    cout<<"Please enter the vexnum and arcnum of the G graph"<<endl;    cin>>G.vexnum>>G.arcnum; cout<<"Please enter the dians of G"<<endl;    for(int i=0;i!=G.vexnum;++i){cin>>G.vexs[i];}//构造顶点向量    for(int i=0;i!=G.vexnum;++i){//初始化矩阵     for(int j=0;j!=G.vexnum;++j){        G.arcs[i][j].adj=10000;        }    }char v1,v2;int w;cout<<"Please enter "<<G.arcnum<<" arcnums"<<endl;for(int k=0;k!=G.arcnum;++k){    cin>>v1>>v2>>w;    int i=locate(G,v1); int j=locate(G,v2);    G.arcs[i][j].adj=w;}}void printgraph(Mgraph M){cout<<"\n"<<"The graph has "<<M.vexnum<<"vertex and "<<M.arcnum<<"arc"<<endl;cout<<"The vertex is:";   for(int i=0;i!=M.vexnum;++i){cout<<M.vexs[i]<<" ";}cout<<endl;    for(int i=0;i!=M.vexnum;++i){     for(int j=0;j!=M.vexnum;++j){         if(M.arcs[i][j].adj!=10000)            cout<<M.vexs[i]<<"   "<<M.vexs[j]<<endl;        }    }   for(int i=0;i!=M.vexnum;++i){     for(int j=0;j!=M.vexnum;++j){         cout<<M.arcs[i][j].adj<<"         ";        }cout<<endl;    }}//单源,某顶点到各顶点的最短路径void Shortestpath(Mgraph G,int v0,int  ppp[][Max_v],int*D){    for(int i=0;i!=Max_v;++i){ //初始化pathbool    for(int j=0;j!=Max_v;++j){    ppp[i][j]=false;}}    bool finals[Max_v];//如果finals[v]为true,则已经求得v0到v的最短路径了    for(int v=0;v!=G.vexnum;++v){        finals[v]=false; D[v]=G.arcs[v0][v].adj; //初始化        for(int w=0;w!=G.vexnum;++w){ ppp[v][w]=false;}//设置空路径            if(D[v]<10000){ppp[v][v0]=true; ppp[v][v]=true;}//目前找到的最短的路径    }    D[v0]=0;finals[v0]=true;//v0属于s集     int v;     //开始主循环,每次求得v0到某个v顶点的最短路径,并加到s集中    for(int i=1;i!=G.vexnum;++i){//其余G.vexnum-1个顶点        int mins=10000;        for(int w=0;w!=G.vexnum;++w){//当前已知离v0最近的点,并把其加到s集中。随后更新已知到顶点的最短长度            if(!finals[w]&&D[w]<mins){  v=w;mins=D[w];}        }finals[v]=true;   for(int w=0;w!=G.vexnum;++w){           if(!finals[w]&&(mins+G.arcs[v][w].adj<D[w])){//w不在s集,更新最短距离            D[w]=mins+G.arcs[v][w].adj;            for(int i=0;i!=Max_v;++i){                ppp[w][i]=ppp[v][i];            }            ppp[w][w]=true;           }        }    }//for}bool yes(Mgraph G,int tem,int j){if(G.arcs[tem][j].adj!=10000)return true;else return false;}//打印结果void printresult(Mgraph G,int v0,int  ppp[][Max_v],int*D){for(int i=0;i!=G.vexnum;++i){    if(i!=v0){            if(D[i]==10000)cout<<" "<<G.vexs[v0]<<"-->>"<<G.vexs[i]<<"     无路径,不可达"<<endl;//路径长度等于最大值,则不可达else{        cout<<" "<<G.vexs[v0]<<"-->>"<<G.vexs[i]<<"  长度:"<<"="<<" "<<D[i]<<"   路径:"<<G.vexs[v0]<<" ";   int tem=v0;    for(int j=0;j!=G.vexnum;++j){//根据数组pathbool来找到路径        if(ppp[i][j]==1&&j!=v0&&j!=i&&yes(G,tem,j)){            cout<<G.vexs[j]<<" " ;   ppp[i][j]=0;tem=j;j=0;    }    }cout<<G.vexs[i]<<endl;}    }}}int main(){ifstream infile("rebuf.txt");streambuf* backup=cin.rdbuf();//记录原状态cin.rdbuf(infile.rdbuf());   Mgraph m;   createDG(m);printgraph(m);cout<<endl;int pathbool[Max_v][Max_v];//记录路径,如果pathbool[v][w]为true。则w是v0到v最短路径上的顶点int D[Max_v];//记录当前所找到的从始点到每个终点vi的最短路径的长度Shortestpath(m,0,pathbool,D);//迪杰斯特拉算法,算法7.15cout<<endl;printresult(m,0,pathbool,D);//打印结果cout<<endl;cin.rdbuf(backup);//解绑重定向//利用迪杰斯特拉算法来求一对顶点之间的最短路径cout<<"请输入起点";char x,y;cin>>x;Shortestpath(m,locate(m,x),pathbool,D);cout<<"请输入终点";cin>>y;int iy=locate(m,y);if(D[iy]==10000)cout<<"不可达"<<endl;else{ cout<<" "<<m.vexs[locate(m,x)]<<"-->>"<<m.vexs[iy]<<"  长度:"<<"="<<" "<<D[iy]<<"   路径:"<<m.vexs[locate(m,x)]<<" ";   int tem=locate(m,x);    int i=iy;    for(int j=0;j!=m.vexnum;++j){//根据数组pathbool来找到路径        if(pathbool[i][j]==1&&j!=locate(m,x)&&j!=i&&yes(m,tem,j)){//类似上面打印结果,这次只需打印一个路径            cout<<m.vexs[j]<<" " ;   pathbool[i][j]=0;tem=j;j=0;    }    }cout<<m.vexs[i]<<endl;}  return 0;}

rebuf.txt:

6 8
a b c d e f 
a c 10
a e 30 
a f 100
b c 5
c d 50
d f 10
e d 20
e f 60



运行结果:


2.每一对顶点之间的最短路径

首先可以利用迪杰斯特拉算法来解决,上面最后已经给出了方法。

下面使用弗洛伊德算法,时间复杂度相同,但是形式上更加简洁。


过了一个春节,有好几天没动,真是罪过,今天总算把艰苦的第七章给结束了,Floyd算法。

直接上代码:

#include<iostream>#include<fstream>#define Max_v 200using namespace std;//算法7.16 最短路径,Floyd算法struct Arccell{int adj;};typedef Arccell adjmatric[Max_v][Max_v];struct Mgraph{char vexs[Max_v];   //顶点向量adjmatric arcs;   //邻接矩阵int  vexnum,arcnum;  //顶点数 和 弧数};int locate(Mgraph G,char ch){for(int i=0;i!=G.vexnum;++i){    if(G.vexs[i]==ch)return i;}}void createDG(Mgraph &G){//采用数组表示法,构造有向图    cout<<"Please enter the vexnum and arcnum of the G graph"<<endl;    cin>>G.vexnum>>G.arcnum; cout<<"Please enter the dians of G"<<endl;    for(int i=0;i!=G.vexnum;++i){cin>>G.vexs[i];}//构造顶点向量    for(int i=0;i!=G.vexnum;++i){//初始化矩阵     for(int j=0;j!=G.vexnum;++j){            if(i==j)G.arcs[i][j].adj=0;       else G.arcs[i][j].adj=10000;        }    }char v1,v2;int w;cout<<"Please enter "<<G.arcnum<<" arcnums"<<endl;for(int k=0;k!=G.arcnum;++k){    cin>>v1>>v2>>w;    int i=locate(G,v1); int j=locate(G,v2);    G.arcs[i][j].adj=w;}}void printgraph(Mgraph M){cout<<"\n"<<"The graph has "<<M.vexnum<<"vertex and "<<M.arcnum<<"arc"<<endl;cout<<"The vertex is:";   for(int i=0;i!=M.vexnum;++i){cout<<M.vexs[i]<<" ";}cout<<endl;    for(int i=0;i!=M.vexnum;++i){     for(int j=0;j!=M.vexnum;++j){         if(M.arcs[i][j].adj!=10000)            cout<<M.vexs[i]<<"   "<<M.vexs[j]<<endl;        }    }   for(int i=0;i!=M.vexnum;++i){     for(int j=0;j!=M.vexnum;++j){         cout<<M.arcs[i][j].adj<<"         ";        }cout<<endl;    }}bool yes(Mgraph G,int tem,int j){if(G.arcs[tem][j].adj!=10000)return true;else return false;}//算法7.16void Short_path_floyd(Mgraph G,int p[3][3][3],int D[3][3]){//若p[v][w][u]为true,则U为v到w当前求得最短路径上的顶点for(int v=0;v!=G.vexnum;++v){    for(int w=0;w!=G.vexnum;++w){D[v][w]=G.arcs[v][w].adj;for(int u=0;u!=G.vexnum;++u){p[v][w][u]=false;}if(D[v][w]<10000){//从v到w有直接路径,设置p    p[v][w][v]=true;    p[v][w][w]=true;}}}for(int u=0;u!=G.vexnum;++u){//最主要过程,不断的用u作为中间点,寻找最短路径    for(int v=0;v!=G.vexnum;++v){      for(int w=0;w!=G.vexnum;++w){        if(D[v][u]+D[u][w]<D[v][w]){            D[v][w]=D[v][u]+D[u][w];            for(int i=0;i!=G.vexnum;++i){                p[v][w][i]=p[v][u][i];}//v到u上的点也是v到w上的点        }      }}}}int main(){ifstream infile("rebuf.txt");streambuf* backup=cin.rdbuf();//记录原状态cin.rdbuf(infile.rdbuf());   Mgraph m;   createDG(m);printgraph(m);cout<<endl;int p[3][3][3];//p[v][w][u]=true,则表示u为当前求得最短路径上的顶点,p起到记录到作用int d[3][3];//实时跟新v到w的最短路径长度Short_path_floyd(m,p,d);cin.rdbuf(backup);cout<<"请输入起点";char x,y;cin>>x;int ix=locate(m,x);cout<<"请输入终点";cin>>y;int iy=locate(m,y); cout<<" "<<m.vexs[ix]<<"-->>"<<m.vexs[iy]<<"  长度:"<<"="<<" "<<d[ix][iy]<<"   路径:"<<m.vexs[ix]<<" ";p[ix][iy][ix]=0;p[ix][iy][iy]=0;int tem=ix;for(int i=0;i!=m.vexnum;++i){    if(p[ix][iy][i]==1&&yes(m,tem,i)){cout<<m.vexs[i]<<" ";p[ix][iy][i]=0;    tem=i;    i=0;}}  cout<<m.vexs[iy]<<endl;  return 0;}

rebuf.txt:

3 5
a b c
a b 5
a c 11
b a 6
b c 2
c a 3

书上图7.36

运行结果:




0 0