【数据结构】最短路径

非网图中,最短路径是指两顶点之间经历的边数最少的路径。
网图中,最短路径是指两顶点之间经历的边上权值之和最短的路径。

单源点到其他顶点的最短路径

Dijkstra方法,O(n2)

任意一对顶点之间的最短路径

Floyed方法,O(n3)

单源点最短路径问题

问题描述:

给定带权有向图G=(V, E)和源点v∈V,求从v到G中其余各顶点的最短路径。

迪杰斯特拉(Dijkstra)提出了一个按路径长度递增的次序产生最短路径的算法——Dijkstra算法。

  • 路径长度递增的理解
    含有n个顶点的图,计算图中顶点v到其他顶点(n-1个)的最短路,总共要找多少条最短路?
    —>n-1条
    按路径长度递增指的是这n-1条路的计算原则即,
    先找第一条最短路(v,vi),所有n-1条路中最短的路
    再找第二条最短路(v,vj)
    ……

基本思想:

1.设置一个集合S存放已经找到最短路径的顶点,S的初始状态只包含源点v,
2.对vi∈V-S,假设从源点v到vi的有向边为最短路径(从v到其余顶点的最短路径的初值)。
3.以后每求得一条最短路径v, …, vk,就将vk加入集合S中,并将路径v, …, vk , vi与原来的假设相比较,取路径长度较小者为最短路径。
重复上述过程,直到集合V中全部顶点加入到集合S中。

路径长度最短的最短路径(即第一条最短路)的特点:

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

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

它只可能有两种情况:
或者是直接从源点到该点(只含一条边);
或者是从源点经过顶点v1(第一条最短路径所依附的顶点),再到达该顶点(由两条边组成)。

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

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

其余最短路径的特点:

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

数据结构

图的存储结构:邻接矩阵存储结构
数组dist[n]:每个分量dist[i]表示当前所找到的从始点v到终点vi的最短路径的长度。初态为:若从v到vi有弧,则dist[i]为弧上权值;否则置dist[i]为∞。
数组path[n]:path[i]是一个字符串,表示当前所找到的从始点v到终点vi的最短路径。初态为:若从v到vi有弧,则path[i]为vvi;否则置path[i]空串。
数组s[n]:存放源点和已经找到最短路径的终点,其初态为只有一个源点v。

迪杰斯特拉算法的主要步骤如下:

(1) g为用邻接矩阵表示的带权图。
S←{v0} , dist[i]= g.arcs[v0][vi]
,path[i]=“v0vi”或“”;
将v0到其余顶点的路径长度初始化为权值;
(2) 选择vk,使得 vk为目前求得的下一条从v0出发的最短路径的终点。
将vk加入到S中
(3) 修改从v0出发到集合V-S上任一顶点vi的最短路径的长度。如果dist[k]+ g.arcs[k][i]<dist[i]则将dist[i]修改为dist[k]+ g.arcs[k][i] path[i]=path[k]+”vi”
(4) 重复(2)、(3) n-1次,即可按最短路径长度的递增顺序,逐个求出v0到图中其它每个顶点的最短路径。

const int MAX=1000;
void  Dijkstra(MGraph g, int v){
       for ( i =0; i<g.vexnum ; i++){
	 dist[i]=g.arcs[v][i];  
               if ( dist[i]!= MAX) 
                      path [i]=g.vertex[v]+g.vertex[i];
               else
                      path[i]=“”;
       }
       S[0]=g.vertex[v]; 
       num=1;  
       While (num<g.vextexNum){
    k=0;
    for(i=0;i<G.vertexNum;i++)
           if((dist[i]<dist[k])   
           k=i
    cout<<dist[k]<<path[k];
    s[num++]=G.vertex[k];                
    for(i=0;i<G.vertexNum;i++)
             if(dist[k]+g.arc[k][i]<dist[i] {
		 				dist[i]=dist[k]+g.arc[k][i];
                       	path[i]=path[k]+g.vertex[i];
               }
}
}

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

问题描述:给定带权有向图G=(V, E),对任意顶点vi,vj∈V(i≠j),求顶点vi到顶点vj的最短路径。
解决办法1:每次以一个顶点为源点,调用Dijkstra算法n次。显然,时间复杂度为O(n3)。
解决办法2:弗洛伊德提出的求每一对顶点之间的最短路径算法——Floyd算法,其时间复杂度也是O(n3),但形式上要简单些。

Floyd算法的基本思想如下:

设图g用邻接矩阵法表示, 求图g中任意一对顶点vi、 vj间的最短路径。
(-1) 将vi到vj 的最短的路径长度初始化为(vi,vj), 然后进行如下n次比较和修正:
(0) 在vi、vj间加入顶点v0,比较(vi, v0, vj)和(vi, vj)的路径的长度,取其中较短的路径作为vi到vj的且中间顶点号不大于0的最短路径。
(1) 在vi、vj间加入顶点v1,得(vi, …,v1)和(v1, …,vj),其中:(vi, …, v1)是vi到v1 的且中间顶点号不大于0的最短路径, (v1, …, vj) 是v1到vj 的且中间顶点号不大于0的最短路径,这两条路径在上一步中已求出。
将(vi, …, v1, …, vj)与上一步已求出的且vi到vj 中间顶点号不大于0的最短路径比较,取其中较短的路径作为vi到vj 的且中间顶点号不大于1的最短路径。
(2)在vi、vj间加入顶点v2,得(vi, …, v2)和(v2, …, vj), 其中:(vi, …, v2)是vi到v2 的且中间顶点号不大于1的最短路径,(v2, …, vj) 是v2到vj 的且中间顶点号不大于1的最短路径,这两条路径在上一步中已求出。将(vi, …, v2, …, vj)与上一步已求出的且vi到vj 中间顶点号不大于1的最短路径比较, 取其中较短的路径作为vi到vj 的且中间顶点号不大于2的最短路径。
……

数据结构

在这里插入图片描述

void Floyd(MGraph G)
{
    for (i=0; i<G.vertexNum; i++)        
       for (j=0; j<G.vertexNum; j++)
       {
          dist[i][j]=G.arc[i][j];
          if (dist[i][j]!=) 
               path[i][j]=G.vertex[i]+G.vertex[j];
          else path[i][j]=""; 
       }
            for (k=0; k<G.vertexNum; k++)         
        for (i=0; i<G.vertexNum; i++)       
           for (j=0; j<G.vertexNum; j++)
               if (dist[i][k]+dist[k][j]<dist[i][j]) {
                    dist[i][j]=dist[i][k]+dist[k][j];
                    path[i][j]=path[i][k]+path[k][j];
              }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值