在前面的文章《所有节点对的最短路径问题》中,我们介绍了用于稀疏图的Johnson算法,由于代码比较长,我们将其单独放在一篇文章之中。

Johnson算法的时间复杂度在使用二叉堆作为最小优先队列的情况下为O((V^2 + EV)lgV);在使用斐波那契堆作为最小优先队列的时候为O(V^2lgV + VE),因此尤其是在稀疏图的情况下,其效率要比Floyd-Warshall高。

下面给出Java实现的代码:

import java.util.*;
public class Johnson{static final int MAX = 20;  //最大点数static int[][] g;static int[] h = new int[MAX];
//  static LinkedList<Elem> S = new LinkedList<Elem>();  static PriorityQueue<Elem> Q = new PriorityQueue<Elem>(); //Q = V-S  static ArrayList<Elem> nodes = new ArrayList<Elem>();static int[][] D;static int ver;  //节点数static int edge; //边数static final int BELLMAN_FORD = 1;static final int DIJKSTRA = 2;/************全局数据结构****************/static class Elem implements Comparable<Elem>  {  public int s; //节点编号 public int d;  //与源节点距离public Elem(int s,int d){  this.s = s;  this.d = d;  }public int compareTo(Elem e){return d - e.d;}  }/***********以下是Johnson算法实现*******************/static void johnson(){int s = ver; //新添加一个节点int[][] g_new = new int[ver+1][ver+1];for(int u = 0;u < g_new.length;u++){for(int v = 0;v < g_new.length;v++){if(v == g.length){g_new[u][v] = Integer.MAX_VALUE;continue;}if(u == g.length){g_new[u][v] = 0; continue;}g_new[u][v] = g[u][v];}}if(bellman_ford(g_new,s) == false) {System.out.println("circle exist");return;}for(Elem e:nodes) h[e.s] = e.d;System.out.println("h[v]: from 0 to n");for(int i = 0;i<g.length;i++) System.out.print(h[i]+" "+'\t');System.out.println();for(int u = 0;u < ver;u++){for(int v = 0;v < ver;v++){if(g[u][v] == Integer.MAX_VALUE) continue;g[u][v] = g[u][v] + h[u]-h[v];}}System.out.println("G' :");initD(g);print(g);for(int u = 0;u < ver;u++){dijkstra(g,u);for(int v = 0;v < ver;v++){if(nodes.get(v).d == Integer.MAX_VALUE) continue;D[u][v] = nodes.get(v).d + h[v] - h[u];}}System.out.println("D[i][j]: shortest path from i to j");print(D);}public static void main(String[] args){input();johnson();}/***初始化函数:可用于Bellman-Ford与Dijkstra的初始化*******/static void init(int[][] g,int source,int mode){ nodes.clear(); for(int i=0; i < g.length;i++){  //初始S为空,Q为全部节点  Elem e = new Elem(i,Integer.MAX_VALUE);  nodes.add(e);  if(i == source && mode == DIJKSTRA) Q.add(e);}nodes.get(source).d = 0;}static void initD(int[][] g){    for(int i = 0;i < g.length;i++)    for(int j = 0;j < g.length;j++){    D[i][j] = g[i][j];    }    }    /*********以下是Bellman-Ford实现***********/static boolean bellman_ford(int[][] g,int source){    init(g,source,BELLMAN_FORD);   int s=0,e=0,w=0;      for(int i=0;i < g.length-1;i++){    //对所有的边进行松弛操作for(int u = 0;u < g.length;u++){for(int v = 0;v < g.length;v++){if(g[u][v] == Integer.MAX_VALUE||nodes.get(u).d == Integer.MAX_VALUE) continue;nodes.get(v).d = Math.min(nodes.get(v).d, nodes.get(u).d + g[u][v]);}}}    //遍历每条边    for(int u = 0;u < g.length;u++){for(int v = 0;v < g.length;v++){ if(g[u][v] == Integer.MAX_VALUE||nodes.get(u).d == Integer.MAX_VALUE) continue;if(nodes.get(v).d > nodes.get(u).d + g[u][v]) return false;}}    return true;    }/************以下是Dijkstra实现*************/static void dijkstra(int[][] g,int source){  init(g,source,DIJKSTRA);while(Q.size() > 0){  Elem u = Q.poll();
//          S.add(u);  for(int v = 0;v < g.length;v++){  if(g[u.s][v] != Integer.MAX_VALUE && nodes.get(v).d > u.d + g[u.s][v]){  Elem nv = nodes.get(v);  //下面删除后添加是为了使PriorityQueue能够重新调整  Q.remove(nv);  nv.d = u.d + g[u.s][v];  Q.offer(nv);  }  }  }}/**************用于获取输入数据,初始化图G的***************/static void input(){  Scanner cin = new Scanner(System.in);  System.out.println("请输入 点数 边数");  ver = cin.nextInt();  edge = cin.nextInt();  g  = new int[ver][ver];D = new int[ver+1][ver+1];int s,e,w;for(int i = 0;i < ver;i++){for(int j = 0;j < ver;j++) {g[i][j] = Integer.MAX_VALUE;}}System.out.println("起点 终点 权值");  for(int i=0;i<edge;i++){  s = cin.nextInt();  e = cin.nextInt();  w = cin.nextInt();  g[s][e] = w;  }  }/************打印前驱矩阵**************/static void print(int[][] g){for(int u = 0;u < ver;u++){for(int v = 0;v < ver;v++){if(g[u][v] == Integer.MAX_VALUE){System.out.print("inf\t"); continue;}System.out.print(g[u][v]+""+'\t');}System.out.println();}}
}

运行如下:

请输入 点数 边数
5 6
起点 终点 权值
0 1 -3
0 3 -5
0 2 4
3 2 2
3 4 3
4 1 -3

运行结果如下:

h[v]: from 0 to n
0     -5     -3     -5     -2     
G' :
inf    2    7    0    inf    
inf    inf    inf    inf    inf    
inf    inf    inf    inf    inf    
inf    inf    0    inf    0    
inf    0    inf    inf    inf    
D[i][j]: shortest path from i to j
0    -5    -3    -5    -2    
inf    0    inf    inf    inf    
inf    inf    0    inf    inf    
inf    0    2    0    3    
inf    -3    inf    inf    0

稀疏图Johnson算法相关推荐

  1. 算法导论——所有点对最短路径:稀疏图Johnson算法

    2019独角兽企业重金招聘Python工程师标准>>> package org.loda.graph;import org.loda.structure.Stack; import ...

  2. 图的最短路径算法及matlab实现(Dijkstra算法、Floyd算法、Bellman-Ford算法、Johnson 算法)

    图的最短路径算法 Dijkstra算法 Dijkstra算法研究的是从初始点到其他任一结点的最短路径,即单源最短路径问题,其对图的要求是不存在负权值的边. Dijkstra算法主要特点是以起始点为中心 ...

  3. 二十九、搜索与图论——克鲁斯卡尔算法(Kruskal 算法,稀疏图)

    Kruskal算法主要内容 一.基本思路 1.基本思想与概念 2.算法步骤 3.注意 二.Java.C语言模板实现 三.例题题解 一.基本思路 1.基本思想与概念 解决问题: 多个城市中铺公路,使城市 ...

  4. Dijkstra算法(堆优化版求稀疏图最短路)

    南昌理工acm集训队 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959年提出的,是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题. 基本思想 Dijkstra算法是用来解决不 ...

  5. python 拓扑排序 dfs bfs_图遍历算法之DFS/BFS

    在计算机科学, 图遍历(Tree Traversal,也称图搜索)是一系列图搜索的算法, 是单次访问树结构类型数据(tree data structure)中每个节点以便检查或更新的一系列机制.图遍历 ...

  6. 所有结点对的最短路径问题之Johnson算法

    Johnson算法可以在O(V*V lgV + VE)的时间内找到所有节点对之间的最短路径,对于稀疏图来说,算法的渐进表现要由于重复平方法和FloydWarshall算法,如果图没有权值为负值的环路, ...

  7. 【技巧】浅谈Johnson算法

    简介 Johnson算法主要用于求稀疏图上的全源最短路径.其主体思想是利用重赋权值的方法把一个原问题带负权的图转化为权值非负的图.然后再使用N次Dijkstra算法以求出全源最短路. --姜碧野< ...

  8. 算法——所有节点对的最短路径:Floyd-Warshall算法、Johnson算法

    前言 前面介绍了单源最短路径问题,本文是介绍所有节点对的最短路径问题,首先我们会想到用前面所介绍的知识来求解该问题,根据不同类型的图可以用一下几种方法求解: 若无权重的图,则可以使用次BFS,时间复杂 ...

  9. 【算法学习】图相关算法编程实现-深度优先遍历和广度优先遍历

    一.图的表示 图G=(V,E).要表示一个图,通常有两种方法:邻接表和邻接矩阵.两种方法都既可以表示有向图,也可以表示无向图. 邻接表表示由一个包含|V|个列表的数组组成,其中每个列表对应V中的一个顶 ...

最新文章

  1. 使用 vue filters过滤器直接显示 几分钟前 几小时前 几天前
  2. 汇编: 描述内存长度
  3. 实现在Android开发中的Splash Screen开场屏的效果
  4. vue中前端处理token过期的方法与axios请求拦截处理
  5. 创业周年记:召唤神龙一周年小记
  6. 这部日本「神作」彻底拉低了我入门AI的门槛
  7. 【操作系统】笔记6 java基本类型及运算
  8. python处理era5_ERA5数据python批量下载程序
  9. 【caffe】Check failed: status == CUDNN_STATUS_SUCCESS (4 vs. 0) CUDNN_STATUS_INTERNAL_ERRO
  10. brew安装软件时报错
  11. Opencv函数 rectangle函数与Rect函数的用法
  12. Mastermind游戏
  13. STM32F103_study50_The punctual atoms(STM32 General timer basic principle )
  14. 艾司博讯:拼多多子账户的操作流程
  15. 2019年终总结——我度过了幸福的一年
  16. java 汉字转拼音原理_java 汉字转拼音
  17. Unity与安卓交互 | Unity2019.3版本之后,在Android Studio中写代码导出aar包与Unity中使用交互的方法
  18. android 三种常用的加密方式
  19. ios学习 准备列表
  20. 32.768K晶振通过CD4060分频后频率过高

热门文章

  1. 数据库课程设计作业报告
  2. Oracle cursor 游标详解
  3. AIX系统月维护查什么(一)
  4. 昆仑万维半年营收近18亿 旗下移动游戏平台启用独立品牌
  5. HTTP Referer(页面统计/资源防盗链)
  6. c语言程序教,C语言程序设计教学方法
  7. 哪些进销存软件既好用又免费?
  8. 国内外编译原理课程实践教学现状分析
  9. 【Unity3D】Android Studio 工程中使用 Java 代码调用 Unity 的 C# 脚本 ( Java 中调用 UnityPlayer#UnitySendMessage 方法 )
  10. 无穷小微积分与考研实践