最短路径Floyd算法具体演示

 

 

 

         演示作品下载 

       源码下载:http://download.csdn.net/detail/vinglemar/8418473

最短路径Floyd算法具体演示

                                                                                  ----VC++来实现路由选择算法

 

摘要:

确定图的路由选择的策略要考虑很多技术因素。其包括:选择最短路由还是最佳路由;Floyd提出图的求每一对顶点之间最短路径的方法,由于好多教材采用的是字符界面算法演示,不是很直观,而且不符合当前windows界面编程趋势。为此,经过反复的探索和实践,充分结合VC++强大而灵活的编程模式,基于对话框MFC,成功完成看似颇难的任务。为后续的进一步演变,创造了一个良好的基础原型。

 

关键字:

网络节点,路由选择,图,有向图和无向图,顶点,最短路径,临接矩阵,Floyd算法,Dijkstra算法

 

 

正文:

通信子网为网络源节点和目的节点提供多条传输数据的路径。网络是节点在收到一个分组后。要确定向下一个节点传送的路径,这就是路由选择。路由选择是网络层要实现的基本功能。在数据报方式中,网络节点要为每个分组选择路由;而在虚电路方式中,只需在连接建立时确定路由。

若要建立一个路由信息系统,可用一个带权的图来表示一个网络。用图的顶表示地点,用图中的边表示两地之间的信息路线,每条边上所附的权值表示该路线的----------。根据实际情况,该图可以是有向图和无向图。我们暂以最短路径表示其权值。在图甲所示的带权的有向图中,从V0V2有两条不同路径:(V0,V1,V2)(V0,V3,V4,V2),前者路径长度为90,后者路径长度为80,即为最短路径。 

 

 

 

 

 

 


如果给定一个出发点(单源点)和一个有向网 G=(V,E),欲求出源点到其他各定点之间的最短路径,迪杰斯特拉(Dijkstra)提出了按路径长度的递增次序,逐步产生最短路径的算法。算法思想:设集合S存放已经求出的最短路径的终点,初始状态时,集合S中只有一个源点,不妨设为V0。以后每求得一条最短路径(V0,V1,…,Vk),就将Vk加入到集合S中,直到全部顶点都加入到集合S中。

为此引入一个附助数组dist[],它的每一个分量dist[i]表示当前从源点V0Vi的最短路径长度。它的初始状态:若从源点V0到顶点Vi有边,则dist[i]为该边上的权值;若从源点到顶点Vi没有边,则dist[i]MAXNUM

显然,路径长度为dist[j]=min{dist[I]|ViV-v0}的路径是从V0出发的长度最短路径,即为(V0,Vj),随即将Vj加入到集合S中。如何求得下一条最短路径?由于V0Vj的最短路径已求得,可能引起V0到其余顶点的当前最短路径长度发生变化,V0Vk的当前最短路径长度只能是(V0,Vk)(V0,Vj,Vk)的小者。

假设S是已求得的最短路径的终点集合,可以证明:下一条最短路径(设终点为Vt)或者是(V0,Vt),或者是中间只经过S中顶点便可到达顶点Vt的路径。这可以用反证法证明:设在此路径上存在一个顶点Vp不在S中,则说明V0Vp的路径长度比V0Vt的最短路径长度还短。然而这是不可能的,因为我们是按照最短路径长度递增的次序来逐次产生各条最短路径的,因此,长度比这条路径短的所有路径均已产生,而且它们的终点也一定已在集合S中,故假设不成立。

因此,在一般情况下,下一条长度最短最短路径长度为dist[k]=min{dist[i]/ViV-S}

在每次求得一条最短路径之后,其终点Vk加入集合S,然后对所有的ViVS,修改其当前最短路径长度dist[i]=min{dist[i],dist[k]+Edge[k][i]},其中,Edge[k][i]是边(Vk,Vi)上的权值。下面给出Dijkstra算法:

const int NumVer=0;//

class Graph

{

private:

 float Edge[NumVex][NumVex];//图的临接矩阵

 float dist[NumVex];//存放从顶点V到其它各顶点的当前最短路径长度。

 int path[NumVex];

int S[NumVex];//存放已求得的在最短路径上的顶点

           public:

void ShortestPath_Dijkstra(int ,int);

int choose(int);

};

void Graph::ShortestPath_ Dijkstra(int n ,int v)

{

 for(int i=0;i<n;i++)

{

 //dist,path,S的初始化

                    dist[i]=Edge[v][i];

                       S[i]=0;

                        If(I!=v;&&dist[I]<MAXNUM)

path[I]=v;

else

 Path[I]=-1;

}

s[v]=1;

dist[v]=0;//顶点v加入已求出最短路径的顶点集合

for(i=0;i<n-1;i++)

{

 float min=MAXNUM;

 int u=v;

 for(int j=0;j<n;j++)//选择当前不在集合S中具有最短路径的顶点u

 if(!S[j]&&dist[j]<min)]

{
     u=j;

 min=dist[j];

}

S[u]=1;//顶点u加入已求出最短路径的顶点集合

for(int w=0;w<n;w++) //修改其余顶点的当前最短路径

if(!S[w]&&Edge[u][w]<MAXNUM&&dist[u]+Edge[u][w]<dist[w])

{

 dist[w]=dist[u]+Edge[u][w];

 path[w]=u;

}

}

  }

  如果要按求出每对顶点之间的最短路径,须分别以每个顶点为源点,重复执行Dijkstra算法。这样就求得每对顶点之间的最短路径及最短路径长度.我们使用更直接求解算法,称为Floyd(弗洛伊德)算法。

 带权有向图仍然用邻接矩阵Edge[n][n]表示,Dijkstra算法的基本思想是:设置一个nn的方阵dist[n][n],初始化时,对角线的元素都等于零,表示顶点到自己的路径长度为0,其他元素dist[i][j]Edge[i][j]的值,表示从顶点Vi到的顶点Vj的初试路径长度。该路径不一定是最短路径,尚需进行n次试探。首先考虑顶点V0作为中间顶点,判断路径(Vi,V0,Vj)是否存在,即(Vi,V0)和(V0,Vj)是否存在。如果存在,取(Vi,Vj)(Vi,V0,Vj)的小者为ViVj的当前的最短路径长度distj[i][j],也就是ViVj经过的中间顶点序号不大于0的最短路径长度。其次中间顶点序号可增加考虑顶点V1,因为dist[i][1]dist[1][j]分别为ViV1V1Vj经过的中间顶点序号不大于0的最短路径长度,所以dist[i][1]+dist[1][j]dist[i][j]的小者即为ViVj经过的中间顶点序号不大于1的最短路径长度,作为当前最短路径长度dist[i][j].然后再增加考虑顶点V2,以此类推,考虑所有n个顶点后,dist[i][j]的值就是ViVj的最短路径的长度。

 由于好多教材采用的是字符界面算法演示,不是很直观,而且不符合当前windows界面编程趋势。为此,经过反复的探索和实践,充分结合VC++强大而灵活的编程模式,基于对话框MFC,成功完成看似颇难的任务。

从下图界面可知,此带权有向图顶点假设为V0,V1,…V18,V19,共20个,两点之间有单向的,也有双向的。有向图实际分成两个不相通的两部分。如果用户任选两个顶点,比如V0及V13(注意:先点击V0的为源点,后点击的V13为目的点,超过两个或一个无效),然后点击开始按钮,通过后台的一系列界面事件处理代码及Floyd(弗洛伊德)算法运算,然后把路径显示在相应窗口中,比如13<<9<<5<<6<<4<<0,它代表路径为:V0->V4->V6->V5->V9->V13同时。路径总长为47。如果两顶点不通,路径及总长度无效。

 

  

 

下面分析一下其中主要算法:

首先在CGraphFloydDlg中,建立三个private的变量:

int iVertexFlag1;

int iVertexFlag2;

int iVertexSelected;

控制源及目的顶点的选择及顺序。

然后在CGraphFloydDlg的实现文件中,建立

int Edge[20][20];

int Dist[20][20];

int Path[20][20];//其中Path[i][j]是相应路径上顶点j的前一顶点的顶点号。

const int MAXNUM = 9999;//

找到BOOL CGraphFloydDlg::OnInitDialog()函数,在其中添加如下代码:

// TODO: Add extra initialization here

   

   iVertexSelected=0;

   iVertexFlag1=-1;

   iVertexFlag2=-1;      

   for(int i=0;i<20;i++)

               for(int j=0;j<20;j++)

               {

                           if(i==j)

                                       Edge[i][j]=0;

                           else

                                       Edge[i][j]=MAXNUM;

               }

 

  Edge[0][2]=20,Edge[0][4]=12;

   Edge[1][0]=10;

   Edge[2][5]=22;

   Edge[3][1]=14;

   Edge[4][3]=33,           Edge[4][6]=8;

   Edge[5][4]=11,Edge[5][9]=7;

   Edge[6][4]=8,Edge[6][5]=6,Edge[6][12]=56;

   Edge[7][8]=13,Edge[7][10]=19,Edge[7][11]=16;

   Edge[8][7]=13;

  Edge[9][5]=7,Edge[9][13]=14;

   Edge[10][14]=22;

   Edge[11][7]=16,Edge[11][14]=77,     Edge[11][15]=13;

   Edge[12][6]=56,Edge[12][13]=21;

   Edge[13][12]=21,Edge[13][16]=8,Edge[13][17]=22;

  Edge[14][11]=77 ,Edge[14][19]=9 ;

  Edge[15][11]=13,Edge[15][18]=11;

  Edge[16][17]=23;

   Edge[17][12]=26;

  Edge[18][15]=11;

  Edge[19][18]=88;

   

通过以上代码完成对图的顶点选择变量及临接矩阵的初始化。邻接矩阵的初始值实为上述图片中,所标注的顶点之间的值。

假如选择V0顶点时,将要触发

void CGraphFloydDlg::OnV0()

{

   // TODO: Add your control notification handler code here

   CButton *p0=(CButton *)GetDlgItem(IDC_V0);

   if((!p0->GetCheck())&&(iVertexSelected>0))

   {

               iVertexSelected--;

               if(iVertexFlag1==0)

               {

                           iVertexFlag1=iVertexFlag2;

                   iVertexFlag2=-1;

               }

               else if(iVertexFlag2==0)

           iVertexFlag2=-1;

   }

 

   else if((iVertexSelected==0)&&(p0->GetCheck()))

   {

               iVertexSelected++;

       iVertexFlag1=0;

   }

   else if((iVertexSelected==1)&&(p0->GetCheck()))

   {

               iVertexSelected++;

       iVertexFlag2=0;

   }

 else if((iVertexSelected>=2)&&(p0->GetCheck()))

   {

               AfxMessageBox("顶点数不容许超过2!");

      p0->SetCheck(FALSE);

   }          

}

假如选择V13顶点时,将要触发

void CGraphFloydDlg::OnV13()

{

   // TODO: Add your control notification handler code here

   CButton *p13=(CButton *)GetDlgItem(IDC_V13);

   if((!p13->GetCheck())&&(iVertexSelected>0))

   {

               iVertexSelected--;

               if(iVertexFlag1==13)

               {

                           iVertexFlag1=iVertexFlag2;

                   iVertexFlag2=-1;

               }

               else if(iVertexFlag2==13)

           iVertexFlag2=-1;

   }

 

   else if((iVertexSelected==0)&&(p13->GetCheck()))

   {

               iVertexSelected++;

       iVertexFlag1=13;

   }

   else if((iVertexSelected==1)&&(p13->GetCheck()))

   {

               iVertexSelected++;

       iVertexFlag2=13;

   }

 else if((iVertexSelected>=2)&&(p13->GetCheck()))

   {

               AfxMessageBox("顶点数不容许超过2!");

      p13->SetCheck(FALSE);

   }          

}

一方面判断顶点的选择顺序情况,修改相应的变量,另一方面,控制用户选择的数量,如果不符合要求,会取消当前操作。

对于其他顶点的触发,同样会执行类似的函数。

当用户选择好顶点时,点击开始按钮,将执行如下函数:

void CGraphFloydDlg::OnStart()

{

   // TODO: Add your control notification handler code here

               if(iVertexSelected==2)

   {

               for( int i=0;i<20;i++)

               for(int j=0;j<20;j++)

               {

                           Dist[i][j]=Edge[i][j];//初始化dist

                           if((i!=j)&&Dist[i][j]<MAXNUM)

                                       Path[i][j]=i;

                           else

                                       Path[i][j]=-1;

               }

 

               for(int k=0;k<20;k++)//逐次增加中间顶点k

                           for(int m=0;m<20;m++)

                                       for(int n=0;n<20;n++)

                                       {

                                                   if(Dist[m][k]+Dist[k][n]<Dist[m][n])//当前最短路径经过中间顶点k

                                                   {

                                                               Dist[m][n]=Dist[m][k]+Dist[k][n];                           

                                                               Path[m][n]=Path[k][n];

                                                   }                                              

                                       }                                                                                                          

               

    m_iMinLen=Dist[iVertexFlag1][iVertexFlag2];    

    int iPath=iVertexFlag2;

   m_strVs="";

   CString strTemp; 

   strTemp.Format("%d<<",iVertexFlag2);

    m_strVs+=strTemp;           

    while(Path[iVertexFlag1][iPath]>-1)

    {         

    

    strTemp.Format("%d<<",Path[iVertexFlag1][iPath]);

   m_strVs+=strTemp;

   iPath=Path[iVertexFlag1][iPath];                  

    }         

    m_strVs.TrimRight("<<");

   if(        m_iMinLen==MAXNUM)

               {

                           m_iMinLen=-1;

                  m_strVs="此路不通!";

               }

   UpdateData(FALSE);

   }

   else

   {

   m_strVs=" 请选则两个有向点。";

   m_iMinLen=-1;

  UpdateData(FALSE);

   }

}

 

 

 

代码首先判断顶点选择数量是否为合法的二个,如果是,运行Floyd(弗洛伊德)算法,求出最短路径的长度及最短路径字符串。如果只选择一个顶点或两个顶点路径不通,给出提示信息。

确定路由选择的策略要考虑很多技术因素。其包括:选择最短路由还是最佳路由;通信子网采用虚电路操作方式,还是数据报操作方式;采用分布式路由算法,还是集中式路由算法;采用静态路由选择策略,还是动态路由选择策略等。所以,路由选择算法(Routing Algorithm)以及它们使用的数据结构是网络层涉及的一个重要研究领域。                                                                                                                                                                                                                                                                                                                              

 

 演示作品下载 

 

想具体浏览源代码请和作者本人联系。

联系方式:

MSN:broadrare@hotmail.com

主页:http://www.ExeSoft.cn

 

参考文献:

1.                  严蔚敏,吴伟民.数据结构(C语言版).北京:清华大学出版社,1996

2.                  张福炎.《〈程序员高级程序员程序设计及〉》(第二版). 北京:清华大学出版社,1996

3.                  黄刘生,唐策善:《《数据结构》》第二版,中国科学技术大学出版社,2000

 

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gCodeTop 格码拓普 老师

您的鼓励.我的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值