dijkstra算法

    技术2024-07-20  65

    dijkstra算法比较容易理解,但是代码有点复杂。

     

     

    求从源点到其余各点的最短路径的算法的基本思想:

     

    其中,从源点到顶点v的最短路径是所有最短短路径中长度最短者。

     

    路径长度最短的最短路径的特点:

    在这条路径上,必定只含一条弧,并且这条弧的权值最小。

     

    下一条路径长度次短的最短路径的特点:

    它只可能有两种情况:或者是直接从源点到该点(只含一条弧); 或者是,从源点经过顶点v1,再到达该顶点(由两条弧组成)。

     

    再下一条路径长度次短的最短路径的特点:

    它可能有三种情况:或者是,直接从源点到该点(只含一条弧); 或者是,从源点经过顶点v1,再到达该顶点(由两条弧组成);或者是,从源点经过顶点v2,再到达该顶点

     

    其余最短路径的特点:

    它或者是直接从源点到该点(只含一条弧); 或者是,从源点经过已求得最短路径的顶点,再到达该顶点

    试用范围:

    1.dijkstra算法实现单源最短路径查找,路径查找2.有向图和无向图都可以使用本算法,无向图中的每条边可以看成相反的两条边。 3.用来求最短路的图中不能存在负权边。

     

    具体实现请看算法,下图为简单测试图例

     #include<iostream> using namespace std; const int MAXNUM=101; int MAP[MAXNUM][MAXNUM]={ {INT_MAX, 2,INT_MAX,INT_MAX,INT_MAX, 9, 15,INT_MAX,INT_MAX}, {INT_MAX,INT_MAX, 4,INT_MAX,INT_MAX,INT_MAX, 6,INT_MAX,INT_MAX}, {INT_MAX,INT_MAX,INT_MAX, 2,INT_MAX,INT_MAX,INT_MAX,INT_MAX, 15}, {INT_MAX,INT_MAX,INT_MAX,INT_MAX, 1,INT_MAX,INT_MAX,INT_MAX, 1}, {INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX, 6,INT_MAX, 3,INT_MAX}, {INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX, 11,INT_MAX}, {INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX, 15, 2}, {INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX, 4}, {INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX,INT_MAX} }; int dist[MAXNUM]; //存储s到各点的最短路径 int path[MAXNUM]; //存储s到各点的最短路径中的倒数第二个结点 #define MAXSUM(a,b) ( ((a)!=INT_MAX&&(b)!=INT_MAX) ? ((a)+(b)) : INT_MAX ) void dijkstra(int s,int n) { bool mark[MAXNUM]={false}; //标记s到i是否属于最短路径范畴 mark[s]=true; //标记源点s不属于搜索范围 int i; for(i=0;i<n;++i) { dist[i]=MAP[s][i]; //初始化s到各点的长度 path[i]=s; //path初始化为s,既s为到各结点的路径的倒数第二个结点 } for(i=2;i<n;++i) //循环n-2次就可以找出n-1条最短路径 { int index=s,lowcost=INT_MAX; int j; //在不是最短路径的路径中(mark[j]==false),找出一条最小的路径, //并标记为最新的最短路径(mark[index]=true) for(j=0;j<n;++j) if(mark[j]==false&&dist[j]<lowcost) { index=j; lowcost=dist[j]; } mark[index]=true; //用最新的最短路径更新剩下的非最短路径 //既mark[j]==false的路径 for(j=0;j<n;++j) if(mark[j]==false&&MAXSUM(dist[index],MAP[index][j])<dist[j]) { //dist[j]=min{dist[j],dist[index]+MAP[index][j]} dist[j]=MAXSUM(dist[index],MAP[index][j]); //确定要更新时,同时更新新路径的倒数第二个结点 path[j]=index; } } } void reverse(int a[],int n) { for(int i=0,j=n-1;i<j;++i,--j) swap(a[i],a[j]); } int getpath(int a[],int s,int i) { int count=1; a[0]=i; while(i!=s) { //path[i]存储s到i路径中i的前驱结点 i=a[count++]=path[i]; } reverse(a,count); return count; } int main() { int a[MAXNUM]; for(int k=0;k<9;++k) { dijkstra(k,9); for(int i=0;i<9;++i) if(dist[i]!=INT_MAX) { cout<<char(k+'a')<<"到"<<char(i+'a')<<"最短路径长度为:"; cout<<dist[i]<<endl; int length=getpath(a,k,i); for(int j=0;j<length;++j) cout<<char(a[j]+'a')<<' '; cout<<endl<<endl; } } return 0; }

    dijkstra算法还有另一种实现,利用队列进行优先级管理,时间复杂度为O((n-2)(n-1)/2),上面dijkstra算法实现的时间复杂度为O((n-2)(n-1)),很明显下面的实现效率是上面的两倍

    void dijkstra(int s,int n) { int q[MAXNUM],qf=0,ql=0; //建立一个队列 int i; for(i=0;i<n;++i) //初始化dis,path,q { dist[i]=MAP[s][i]; path[i]=s; //path初始化为s,既s为到各结点的路径的倒数第二个结点 if(i!=s) //将非源点的结点的下标均放进队列 q[ql++]=i; } while(qf<ql-1) //循环n-2次就可以完成 { //找出dist[q[qf~ql-1]]最小者,并记录队列q的下标 int index_min=qf; for(i=qf+1;i<ql;++i) if(dist[q[i]]<dist[q[index_min]]) index_min=i; swap(q[index_min],q[qf]);//保持q[qf]指向最短的,既确定最新的最短路径 //如果找出的最短路径是无路径的,那后面的循环毫无意义,可直接跳出 if(dist[q[qf]]==INT_MAX) break; //用最新的最短路径dist[q[qf]]来更新dist[q[qf+1~ql-1]] //主意q[qf+1~ql-1]均指向非最短路径的路径 for(i=qf+1;i<ql;++i) if(MAXSUM(dist[q[qf]],MAP[q[qf]][q[i]])<dist[q[i]]) { dist[q[i]]=MAXSUM(dist[q[qf]],MAP[q[qf]][q[i]]); path[q[i]]=q[qf]; } ++qf; } }

     

    最新回复(0)