有向图的最短路径算法

最短路径算法属于数据结构的图的应用知识。先介绍基本的图的概念。

图由顶点集和边集组成。(一张图里不就是有顶点和边)。图中边带有方向就是有向图,否则就是无向图。图的存储结构分为邻接表和邻接矩阵。(邻接表主要采用顺序存储和链式存储结合的方式)。采用链接表这种都是对于稀疏图而言的(就是边少对应也就权值少的这种图叫稀疏图),而我采用的是邻接矩阵,因为我的那个图是个稠密图,边的权值很多。采用邻接矩阵存储就是两个方面,一个是用一维数组存储顶点信息,一个是用二位数组存储边的权值信息。

int[][] graph = {  
			{max,221,294,288,max,400,144,219,264,352,462,484},
			{max,max,175,97,306,289,166,94,228,258,349,364},
			{max,max,max,257,464,462,316,275,405,436,523,538},
			{max,max,max,max,205,203,183,79,184,178,256,269},
			{max,max,max,max,max,83,318,243,225,126,83,79},
			{max,max,max,max,max,max,260,207,152,49,60,84},
			{max,max,max,max,max,max,max,107,124,213,321,343},
			{max,max,max,max,max,max,max,max,130,167,269,285},
			{max,max,max,max,max,max,max,max,max,103,204,230},
			{max,max,max,max,max,max,max,max,max,max,108,132},
			{max,max,max,max,max,max,max,max,max,max,max,26},
			{max,max,max,max,max,max,max,max,max,max,max,max}
		};


实际上对于图的遍历分为深度优先搜索和广度优先搜索,而深度优先搜索主要就是尽可能深的去遍历,采用递归的方式。如果了解树的应用中的回溯法和剪支函数就会对递归有很好了解。而我需要对任意一层访问,所以采用广度优先搜索其实和那个树的层序遍历很像。层序遍历需要一个那种暂存的容器记忆正在访问顶点的下一层节点。这种暂存容器就是先进先出的辅助队列。而我的队列都是用一维数组实现的。

最短路径算法思想:

从第一个节点V1开始遍历,就是遍历权值矩阵中第一行权值。找出距离V1最短的节点V2。V1到V2的最短距离为D1,然后从V2开始遍历到其他节点的最短距离,就是遍历权值矩阵中V2所在的行,找出距离V2最短的点V3,最短权值为D2。然后一直遍历到最后一个点。并且还设置一个标记位,标记那些已经访问过的点,就不会被再次访问。我设置访问过的点位true,否则为false。但是还需要考虑一种情况:假设V3到V1的D3,此时D3>D1+D2这种情况问题的实质就是当前选择的直接到的路径比拐一个点再到终点的路径还长,不是最短路径,所以,要加入到整体遍历的情况中进行判断。然后就慢慢遍历吧。

关键代码:

static int MAX_SIZE=12;

private static int[] stationTemp=new int[MAX_SIZE];//存储最短路径经过的点(不包括起始点和终点),如果没有就都设置为0

private static int[] dist=new int[MAX_SIZE];// 最短路径长度

private static int[] prev=new int[MAX_SIZE];// 前驱顶点集合;

/**最短路径算法

 * @param args

 */

public static void dijkstra(int start,int[][] graph,int[] dist,int[] prev){

       int n=dist.length-1;

       if(start<1||start>n)

             return;

       boolean[] marked=new boolean[n+1];//标记

       for(int i=1;i<=n;i++){

             dist[i]=graph[start][i];

             marked[i]=false;

             if(dist[i]==Integer.MAX_VALUE){

                     prev[i]=0;//将所有节点的前驱都设置为空(除了最后一个节点)

             }else{

                     prev[i]=start;//最后一个节点的前驱为第一个开始遍历的节点

             }

        }

       dist[start]=0;

       marked[start]=true;//从start点开始遍历

       for(int i=1;i<n;i++){

             Integer temp=Integer.MAX_VALUE;

             int u=start;

             for(int j=1;j<=n;j++){

                     if((!marked[j])&&(dist[j]<temp)){//遍历出没有被遍历的点并且最短路径小于最大值

                           u=j;

                           temp=dist[j];//将当前遍历出来的最短路径的长度赋值给temp

                     }

              }

/*1.选择出了从start到下一个点u的最短的路径。

2.并将start到u的最短路径长度存入dist[u]中。

*/

             marked[u]=true;//将遍历后选出的点u作为下一次最短路径的始发点,将其标志位为true。

             for(int j=1;j<=n;j++){

                      if((!marked[j])&&(graph[u][j]<Integer.MAX_VALUE)){

                            int newdist=dist[u]+graph[u][j];

                            if(newdist<dist[j]){//如果两段路径相加值newdist小于遍历出来的最短路径就使用newdist作为当前最短路径,并将u设置为其前驱。

                                  dist[j]=newdist;

                                  prev[j]=u;

                             }

                       }

              }

       }

}




  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值