滴水逆向联盟

标题: VC++2012编程演练数据结构《31》狄杰斯特拉算法 [打印本页]

作者: 大灰狼    时间: 2014-8-19 08:52
标题: VC++2012编程演练数据结构《31》狄杰斯特拉算法
狄杰斯特拉算法
 Dijkstra(狄杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。Dijkstra算法是很有代表性的最短路径算法,在很多专业课程中都作为基本内容有详细的介绍,如数据结构,图论,运筹学等等。Dijkstra一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权边。
问题描述
  在无向图 G=(V,E) 中,假设每条边 E 的长度为 w,找到由顶点 V0 到其余各点的最短路径。(单源最短路径)
狄杰斯特拉算法
  狄杰斯特拉(Dijkstra)算法思想  
按路径长度递增次序产生最短路径算法:
  把V分成两组:
  (1)S:已求出最短路径的顶点的集合
  (2)V-S=T:尚未确定最短路径的顶点集合
  将T中顶点按最短路径递增的次序加入到S中,
  保证:(1)从源点V0到S中各顶点的最短路径长度都不大于
  从V0到T中任何顶点的最短路径长度
  (2)每个顶点对应一个距离值
  S中顶点:从V0到此顶点的最短路径长度
  T中顶点:从V0到此顶点的只包括S中顶点作中间
  顶点的最短路径长度
  依据:可以证明V0到T中顶点Vk的最短路径,或是从V0到Vk的
  直接路径的权值;或是从V0经S中顶点到Vk的路径权值之和
  (反证法可证)
  求最短路径步骤
  算法步骤如下:
  1. 初使时令 S={V0},T={其余顶点},T中顶点对应的距离值
  若存在<V0,Vi>,d(V0,Vi)为<V0,Vi>弧上的权值
  若不存在<V0,Vi>,d(V0,Vi)为∝
  2. 从T中选取一个其距离值为最小的顶点W且不在S中,加入S
  3. 对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V0到Vi的
  距离值缩短,则修改此距离值
  重复上述步骤2、3,直到S中包含所有顶点,即W=Vi为止

狄杰斯特拉算法的原理

  首先,引进一个辅助向量D,它的每个分量D表示当前所找到的从始点v到每个终点vi的最短路径的长度。如D[3]=2表示从始点v到终点3的路径相对最小长度为2。这里强调相对就是说在算法过程中D的值是在不断逼近最终结果但在过程中不一定就等于最短路径长度。它的初始状态为:若从v到vi有弧,则D为弧上的权值;否则置D为∞。显然,长度为 D[j]=Min{D | vi∈V} 的路径就是从v出发的长度最短的一条最短路径。此路径为(v,vj)。 那么,下一条长度次短的最短路径是哪一条呢?假设该次短路径的终点是vk,则可想而知,这条路径或者是(v,vk),或者是(v,vj,vk)。它的长度或者是从v到vk的弧上的权值,或者是D[j]和从vj到vk的弧上的权值之和。 一般情况下,假设S为已求得最短路径的终点的集合,则可证明:下一条最短路径(设其终点为X)或者是弧(v,x),或者是中间只经过S中的顶点而最后到达顶点X的路径。因此,下一条长度次短的最短路径的长度必是D[j]=Min{D | vi∈V-S} 其中,D或者是弧(v,vi)上的权值,或者是D[k](vk∈S)和弧(vk,vi)上的权值之和。 狄杰斯特拉算法描述如下: 1)arcs表示弧上的权值。若不存在,则置arcs为∞(在本程序中为MAXCOST)。S为已找到从v出发的最短路径的终点的集合,初始状态为空集。那么,从v出发到图上其余各顶点vi可能达到的最短路径长度的初值为D=arcs[Locate Vex(G,v),i] vi∈V 2)选择vj,使得D[j]=Min{D | vi∈V-S} 3)修改从v出发到集合V-S上任一顶点vk可达的最短路径长度。

打开IDE


我们创建一个工程


类声名如下

[cpp] view plaincopy


  • #if !defined(AFX_GRAPH_H__EDF8E290_EF85_4726_851D_F684E5602E43__INCLUDED_)  
  • #define AFX_GRAPH_H__EDF8E290_EF85_4726_851D_F684E5602E43__INCLUDED_  
  •   
  • #if _MSC_VER > 1000  
  • #pragma once  
  • #endif // _MSC_VER > 1000  
  •   
  • //图的相关数据类型的定义graph.h  
  • //最多顶点数  
  • const int MaxV=10;  
  • //最大权值  
  • const int MaxValue=99;  
  • //定义邻接表中的边结点类型  
  • struct edgenode {  
  •     int adjvex;   //邻接点域  
  •     int weight;   //权值域  
  •     edgenode* next;//指向下一个边结点的链域  
  • };  
  • //定义邻接表类型  
  • typedef edgenode** adjlist;  
  • //邻接矩阵类定义  
  • class AdjMatrix  
  • {private:  
  • char g[MaxV];//顶点信息数组  
  • int size;//当前顶点数  
  • int GA[MaxV][MaxV];//定义邻接矩阵GA  
  • int numE;//当前边数  
  • public:  
  •     //构造函数,初始化图的邻接矩阵  
  •     AdjMatrix(int n,int k2);  
  •     //判断图空否  
  •     bool GraphEmpty() {return size==0;}  
  •     //取当前顶点数  
  •     int NumV() {return size;}  
  •     //取当前边数  
  •     int NumEdges() {return numE;}  
  •     //取顶点i的值  
  •     char GetValue(const int i);  
  •     //取弧<v1,v2>的权  
  •     int GetWeight(const int v1,const int v2);  
  •     //在位置pos处插入顶点V  
  •     void InsertV(const char &V,int pos);  
  •     //插入弧<v1,v2>,权为weight  
  •     void InsertEdge(const int v1,const int v2,int weight);  
  •     //删除顶点i与顶点i相关的所有边  
  •     char DeleteVE(const int i);  
  •     //删除弧<v1,v2>  
  •     void DeleteEdge(const int v1,const int v2);  
  •     //建立图的邻接矩阵  
  •     void CreateMatrix(int n, int k1,int k2);  
  •     //k1为0则无向否则为有向,k2为0则无权否则为有权  
  •     //从初始点vi出发深度优先搜索由邻接矩阵表示的图  
  •     void dfsMatrix(bool*& visited,int i,int n,int k2);  
  •     //从初始点vi出发广度优先搜索由邻接矩阵表示的图  
  •     void bfsMatrix(bool*& visited,int i,int n,int k2);  
  •     //由图的邻接矩阵得到图的邻接表  
  •     void graphChange(adjlist &GL,int n,int k2);  
  •     //检查输入的边序号是否越界,若越界则重输  
  •     void Check(int n,int& i,int& j);  
  •     //由图的邻接矩阵建立图  
  •     void Creatgraph(int n,int k2);  
  •     //对非连通图进行深度优先搜索  
  •     void dfsMatrix(int n,int k2);  
  •     //对非连通图进行广度优先搜索  
  •     void bfsMatrix(int n,int k2);  
  • };  
  •   
  • #endif // !defined(AFX_GRAPH_H__EDF8E290_EF85_4726_851D_F684E5602E43__INCLUDED_)  



类实现如下

[cpp] view plaincopy


  • #include "stdafx.h"  
  • #include "graph.h"  
  •   
  • //图的相关运算的实现graph.cpp  
  • #include"graph.h"  
  • //构造函数,初始化图的邻接矩阵  
  • AdjMatrix::AdjMatrix(int n,int k2)  
  • {int i,j;  
  • if(k2==0){//初始化无(有)向无权图  
  •   for(i=0;i<n;i++)  
  •    for(j=0;j<n;j++)  
  •     GA[j]=0;}  
  • else {//初始化无(有)向有权图  
  •   for(i=0;i<n;i++)  
  •    for(j=0;j<n;j++)  
  •     if(i==j) GA[j]=0;  
  •     else GA[j]=MaxValue;}  
  • size=numE=0;  
  • }  
  • //建立图的邻接矩阵  
  • void AdjMatrix::CreateMatrix(int n,int k1,int k2)  
  • //k1为0则无向否则为有向,k2为0则无权否则为有权  
  • {int i,j,k,e,w;  
  • cout<<"输入图的总边数:";  
  •    cin>>e;  
  • if(k1==0 && k2==0) { //建立无向无权图  
  •   cout<<"输入"<<e<<"条无向无权边的起点和终点序号!"<<endl;  
  •   for(k=1; k<=e; k++) {  
  •    cin>>i>>j;  
  •    Check(n,i,j);  
  •    GA[j]=GA[j]=1;}  
  •   }  
  • else if(k1==0 && k2!=0) { //建立无向有权图  
  •    cout<<"输入"<<e<<"条无向带权边的起点和终点序号及权值!"<<endl;  
  •    for(k=1; k<=e; k++) {  
  •     cin>>i>>j>>w;  
  •     Check(n,i,j);  
  •     GA[j]=GA[j]=w;}  
  •   }  
  •   else if(k1!=0 && k2==0) { //建立有向无权图  
  •     cout<<"输入"<<e<<"条有向无权边的起点和终点序号!"<<endl;  
  •     for(k=1; k<=e; k++) {  
  •      cin>>i>>j;  
  •      Check(n,i,j);  
  •      GA[j]=1;}  
  •   }  
  •   else if(k1!=0 && k2!=0) { //建立有向有权图  
  •     cout<<"输入"<<e<<"条有向有权边的起点和终点序号及权值!"<<endl;  
  •     for(k=1; k<=e; k++) {  
  •      cin>>i>>j>>w;  
  •      Check(n,i,j);  
  •      GA[j]=w;}}  
  •   numE=e;     
  •   cout<<"创建后的邻接矩阵:\n";     
  •   for(i=0;i<n;i++)  
  •   {for(j=0;j<n;j++)  
  •     cout<<setw(4)<<GA[j];  
  •    cout<<endl;}  
  • }  
  • //从初始点vi出发深度优先搜索由邻接矩阵表示的图  
  • void AdjMatrix::dfsMatrix(bool*& visited,int i,int n,int k2)  
  • {cout<<g<<':'<<i<<"  ";  
  • visited=true;        //标记vi已被访问过  
  • for(int j=0; j<n; j++)  //依次搜索vi的每个邻接点  
  •   if(k2==0)  
  •    {if(i!=j&&GA[j]!=0&&!visited[j])  
  •      dfsMatrix(visited,j,n,k2);}  
  •   else  
  •    if(i!=j&&GA[j]!=MaxValue&&!visited[j])  
  •      dfsMatrix(visited,j,n,k2);  
  • }  
  • //从初始点vi出发广度优先搜索由邻接矩阵表示的图  
  • void AdjMatrix::bfsMatrix(bool*& visited,int i,int n,int k2)  
  • {const int MaxLength=30;  
  • //定义一个队列q,其元素类型应为整型  
  • int q[MaxLength]={0};  
  • //定义队首和队尾指针  
  • int front=0,rear=0;  
  • //访问初始点vi  
  • cout<<g<<':'<<i<<"  ";  
  • //标记初始点vi已访问过  
  • visited=true;  
  •   //将已访问过的初始点序号i入队  
  • q[++rear]=i;  
  •   //当队列非空时进行循环处理  
  • while(front!=rear) {  
  •   //删除队首元素,第一次执行时k的值为i  
  •   front=(front+1)%MaxLength;  
  •   int k=q[front];  
  •   //依次搜索vk的每一个可能的邻接点  
  •   for(int j=0;j<n;j++)  
  •    if(k2==0)  
  •     {if(k!=j&&GA[k][j]!=0&&!visited[j])  
  •      {//访问一个未被访问过的邻接点vj  
  •       cout<<g[j]<<':'<<j<<"  ";  
  •       visited[j]=true;     //标记vj已访问过  
  •       rear=(rear+1)%MaxLength;//顶点序号j入队  
  •       q[rear]=j;  
  •      }  
  •     }  
  •    else  
  •     if(k!=j&&GA[k][j]!=MaxValue&&!visited[j])  
  •      {//访问一个未被访问过的邻接点vj  
  •       cout<<g[j]<<':'<<j<<"  ";  
  •       visited[j]=true;   //标记vj已访问过  
  •       rear=(rear+1)%MaxLength;//顶点序号j入队  
  •       q[rear]=j;  
  •      }  
  • }}  
  • //检查输入的边序号是否越界,若越界则重输  
  • void AdjMatrix::Check(int n,int& i,int& j)  
  • {while(1) {  
  •   if(i<0||i>=n||j<0||j>=n)  
  •     cout<<"输入有误,请重输!";  
  •   else return;  
  •   cin>>i>>j;  
  • }  
  • }  
  • //由图的邻接矩阵得到图的邻接表  
  • void AdjMatrix::graphChange(adjlist &GL,int n,int k2)  
  • {int i,j;  
  • if(k2==0)  
  • {for(i=0;i<n;i++){  
  •   for(j=0;j<n;j++)  
  •     if(GA[j]!=0) {  
  •      edgenode* p=new edgenode;  
  •      p->adjvex=j;  
  •      p->next=GL;GL=p;  
  •      cout<<'('<<i<<','<<p->adjvex<<") ";}  
  •   cout<<endl;}}  
  • else {  
  •   for(i=0;i<n;i++){  
  •    for(j=0;j<n;j++)  
  •     if(GA[j]!=0 && GA[j]!=MaxValue) {  
  •      edgenode* p=new edgenode;  
  •      p->adjvex=j;p->weight=GA[j];  
  •      p->next=GL;GL=p;  
  •      cout<<'('<<i<<','<<p->adjvex<<','<<p->weight<<") ";}  
  •    cout<<endl;}  
  • }}  
  • //由图的邻接矩阵建立图  
  • void AdjMatrix::Creatgraph(int n,int k2)  
  • {int i,j,k,m=0;  
  • if(k2==0)  
  • {for(i=0;i<n;i++){  
  •    k=i;  
  •   for(j=0;j<n;j++)  
  •     if(GA[j]!=0)  
  •      if(k==i&&m<n)  
  •       {g[m]='A'+m;size++;  
  •        cout<<g[m]<<'('<<i<<','<<j<<") ";  
  •        m++;  
  •       }  
  •   }  
  •   cout<<endl;}  
  • else {  
  •   for(i=0;i<n;i++){  
  •    k=i;  
  •    for(j=0;j<n;j++)  
  •     if(GA[j]!=0 && GA[j]!=MaxValue)  
  •      if(k==i&&m<n)  
  •       {g[m]='A'+m;size++;  
  •        cout<<g[m]<<'('<<i<<','<<j<<','<<GA[j]<<") ";  
  •        m++;  
  •       }  
  •   }  
  • cout<<endl;}  
  • g[n]='\0';  
  • }  
  • //取顶点i的值  
  • char AdjMatrix::GetValue(const int i)  
  • {if(i<0||i>size)  
  •   {cerr<<"参数i越界!\n";exit(1);}  
  • return g;  
  • }  
  • //取弧<v1,v2>的权  
  • int AdjMatrix::GetWeight(const int v1,const int v2)  
  • {if(v1<0||v1>size||v2<0||v2>size)  
  •   {cerr<<"参数v1或v2越界!\n";exit(1);}  
  • return GA[v1][v2];   
  • }  
  • //在位置pos处插入顶点V  
  • void AdjMatrix::InsertV(const char &V,int pos)  
  • {int i;  
  • if(size==MaxV)  
  •   {cerr<<"表已满,无法插入!\n";exit(1);}  
  • if(pos<0||pos>size)  
  •   {cerr<<"参数pos越界!\n";exit(1);}  
  • for(i=size;i>pos;i--) g=g[i-1];  
  • g[pos]=V;  
  • size++;   
  • }  
  • //插入弧<v1,v2>,权为weight  
  • void AdjMatrix::InsertEdge(const int v1,const int v2,int weight)  
  • {if(v1<0||v1>size||v2<0||v2>size)  
  •   {cerr<<"参数v1或v2越界!\n";exit(1);}  
  • GA[v1][v2]=weight;  
  • numE++;   
  • }  
  • //删除顶点v与顶点v相关的所有边  
  • char AdjMatrix::DeleteVE(const int v)  
  • {for(int i=0;i<size;i++)  
  •   for(int j=0;j<size;j++)  
  •    if((i==v||j==v)&&GA[j]>0&&GA[j]<MaxValue)  
  •     {GA[j]=MaxValue;  
  •      numE--;}  
  • if(size==0)  
  •   {cerr<<"表已空,无元素可删!\n";exit(1);}  
  • if(v<0||v>size-1)  
  •   {cerr<<"参数v越界!\n";exit(1);}  
  • char temp=g[v];  
  • for(int i=v;i<size-1;i++) g=g[i+1];  
  • size--;  
  • g[size]='\0';  
  • return temp;  
  • }  
  • //删除弧<v1,v2>  
  • void AdjMatrix::DeleteEdge(const int v1,const int v2)  
  • {if(v1<0||v1>size||v2<0||v2>size||v1==v2)  
  •   {cerr<<"参数v1或v2出错!\n";exit(1);}  
  • GA[v1][v2]=MaxValue;  
  • numE--;  
  • }  
  • //对非连通图进行深度优先搜索  
  • void AdjMatrix::dfsMatrix(int n,int k2)  
  • {bool *vis=new bool[NumV()];  
  • for(int i=0;i<NumV();i++) vis=false;  
  • for(int i=0;i<NumV();i++)  
  •   if(!vis) dfsMatrix(vis,i,n,k2);  
  • delete []vis;  
  • }  
  • //对非连通图进行广度优先搜索  
  • void AdjMatrix::bfsMatrix(int n,int k2)  
  • {bool *vis=new bool[NumV()];  
  • for(int i=0;i<NumV();i++) vis=false;  
  • for(int i=0;i<NumV();i++)  
  •   if(!vis) bfsMatrix(vis,i,n,k2);  
  • delete []vis;  
  • }  





代码调用如下

[cpp] view plaincopy


  • #include "stdafx.h"  
  •   
  •   
  • #include "graph.h"  
  • //网G从下标v0到其他顶点的最短距离dist和最短路径下标path  
  • void PShortPath(AdjMatrix &G,int v0,int dist[],int path[])  
  • {int n=G.NumV();  
  • int *s=new int[n];  
  • int mindis,i,j,u;  
  • for(i=0;i<n;i++)  
  • {dist=G.GetWeight(v0,i);  
  • s=0;  
  • if(i!=v0&&dist<MaxValue) path=v0;  
  • else path=-1;  
  • }  
  • s[v0]=1;//标记顶点v0已从集合T加入到集合S中  
  • //在当前还未找到最短路径的顶点集中选取具有最短距离的顶点u  
  • for(i=1;i<n;i++)  
  • {mindis=MaxValue;  
  • for(j=0;j<n;j++)  
  • if(s[j]==0&&dist[j]<mindis)  
  • {u=j;  
  • mindis=dist[j];  
  • }  
  • //当已不再存在路径时算法结束;此语句对非连通图是必需的  
  • if(mindis==MaxValue) return;  
  • s=1;//标记顶点u已从集合T加入到集合S中  
  • //修改从v0到其他顶点的最短距离和最短路径  
  • for(j=0;j<n;j++)  
  • if(s[j]==0&&G.GetWeight(u,j)<MaxValue&&  
  •    dist+G.GetWeight(u,j)<dist[j])  
  • {//顶点v0经顶点u到其他顶点的最短距离和最短路径  
  •     dist[j]=dist+G.GetWeight(u,j);  
  •     path[j]=u;  
  • }  
  • }  
  • }  
  • //算法测试  
  • void main()  
  • {cout<<"运行结果:\n";  
  • int n=6,k1=1,k2=1;  
  • AdjMatrix g(n,k2);  
  • g.CreateMatrix(n,k1,k2);  
  • cout<<"\n输出邻接矩阵相应图的每个顶点:\n";  
  • g.Creatgraph(n,k2);  
  • int m=g.NumV();  
  • int *dist=new int[m];  
  • int *path=new int[m];  
  • int v0=0;  
  • PShortPath(g,v0,dist,path);  
  • cout<<"从顶点"<<g.GetValue(v0)  
  • <<"到其他各顶点的最短距离为:\n";  
  • for(int i=0;i<m;i++)  
  • cout<<"到顶点"<<g.GetValue(i)  
  • <<"的最短距离为:"<<dist<<endl;  
  • cout<<"从顶点"<<g.GetValue(v0)  
  • <<"到其他各顶点的最短路径的前一顶点为:\n";  
  • for(int i=0;i<m;i++)  
  • if(path!=-1)  
  • cout<<"到顶点"<<g.GetValue(i)<<"的前一顶点为:"  
  • <<g.GetValue(path)<<endl;  
  • cin.get();cin.get();  

[cpp] view plaincopy


  • }  





效果如下









欢迎光临 滴水逆向联盟 (http://www.dtdebug.com/) Powered by Discuz! X3.2