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

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 200
using 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.15




cout<<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 200
using 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.16
void 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

运行结果:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值