最短路径算法的命令式、函数式版本对比分析

C版本(来自 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)

  1 /***************************************
  2 * About:    有向图的Dijkstra算法实现
  3 * Author:   Tanky Woo
  4 * Blog:     www.WuTianQi.com
  5 ***************************************/
  6
  7 #include <iostream>
  8 using namespace std;
  9
 10 const int maxnum = 100;
 11 const int maxint = 999999;
 12
 13
 14 void Dijkstra(int n, int v, int *dist, int *prev, int c[maxnum][maxnum])
 15 {
 16     bool s[maxnum];    // 判断是否已存入该点到S集合中
 17     for(int i=1; i<=n; ++i)
 18     {
 19         dist[i] = c[v][i];
 20         s[i] = 0;     // 初始都未用过该点
 21         if(dist[i] == maxint)
 22             prev[i] = 0;
 23         else
 24             prev[i] = v;
 25     }
 26     dist[v] = 0;
 27     s[v] = 1;
 28
 29     // 依次将未放入S集合的结点中,取dist[]最小值的结点,放入结合S中
 30     // 一旦S包含了所有V中顶点,dist就记录了从源点到所有其他顶点之间的最短路径长度
 31     for(int i=2; i<=n; ++i)
 32     {
 33         int tmp = maxint;
 34         int u = v;
 35         // 找出当前未使用的点j的dist[j]最小值
 36         for(int j=1; j<=n; ++j)
 37             if((!s[j]) && dist[j]<tmp)
 38             {
 39                 u = j;              // u保存当前邻接点中距离最小的点的号码
 40                 tmp = dist[j];
 41             }
 42         s[u] = 1;    // 表示u点已存入S集合中
 43
 44         // 更新dist
 45         for(int j=1; j<=n; ++j)
 46             if((!s[j]) && c[u][j]<maxint)
 47             {
 48                 int newdist = dist[u] + c[u][j];
 49                 if(newdist < dist[j])
 50                 {
 51                     dist[j] = newdist;
 52                     prev[j] = u;
 53                 }
 54             }
 55     }
 56 }
 57
 58 void searchPath(int *prev,int v, int u)
 59 {
 60     int que[maxnum];
 61     int tot = 1;
 62     que[tot] = u;
 63     tot++;
 64     int tmp = prev[u];
 65     while(tmp != v)
 66     {
 67         que[tot] = tmp;
 68         tot++;
 69         tmp = prev[tmp];
 70     }
 71     que[tot] = v;
 72     for(int i=tot; i>=1; --i)
 73         if(i != 1)
 74             cout << que[i] << " -> ";
 75         else
 76             cout << que[i] << endl;
 77 }
 78
 79 int main()
 80 {
 81     freopen("input.txt", "r", stdin);
 82     // 各数组都从下标1开始
 83     int dist[maxnum];     // 表示当前点到源点的最短路径长度
 84     int prev[maxnum];     // 记录当前点的前一个结点
 85     int c[maxnum][maxnum];   // 记录图的两点间路径长度
 86     int n, line;             // 图的结点数和路径数
 87
 88     // 输入结点数
 89     cin >> n;
 90     // 输入路径数
 91     cin >> line;
 92     int p, q, len;          // 输入p, q两点及其路径长度
 93
 94     // 初始化c[][]为maxint
 95     for(int i=1; i<=n; ++i)
 96         for(int j=1; j<=n; ++j)
 97             c[i][j] = maxint;
 98
 99     for(int i=1; i<=line; ++i)
100     {
101         cin >> p >> q >> len;
102         if(len < c[p][q])       // 有重边
103         {
104             c[p][q] = len;      // p指向q
105             c[q][p] = len;      // q指向p,这样表示无向图
106         }
107     }
108
109     for(int i=1; i<=n; ++i)
110         dist[i] = maxint;
111     for(int i=1; i<=n; ++i)
112     {
113         for(int j=1; j<=n; ++j)
114             printf("%8d", c[i][j]);
115         printf("\n");
116     }
117
118     Dijkstra(n, 1, dist, prev, c);
119
120     // 最短路径长度
121     cout << "源点到最后一个顶点的最短路径长度: " << dist[n] << endl;
122
123     // 路径
124     cout << "源点到最后一个顶点的路径为: ";
125     searchPath(prev, 1, n);
126 }

Java普通版本

 1 import java.util.HashSet;
 2 import java.util.LinkedList;
 3 import java.util.Queue;
 4 import java.util.Set;
 5
 6 public class Dijkstra {
 7     public static class PointInfo{
 8         public int point;
 9         public int prev_point;
10         public int dist;
11         public PointInfo(int p,int pp,int d){
12             point=p;
13             prev_point=pp;
14             dist=d;
15         }
16     }
17     public static void doit_more_abstract(int[][]array){
18         int n=array[0].length;
19         Set<PointInfo> knownSet=new HashSet<PointInfo>();
20         Set<PointInfo> unknownSet=new HashSet<PointInfo>();
21         PointInfo source=new PointInfo(0,-1,0);
22         knownSet.add(source);
23         for(int p=1;p<n;p++){
24             unknownSet.add(new PointInfo(p,-1,Integer.MAX_VALUE));
25         }
26
27         PointInfo nearest=source;
28         while(!unknownSet.isEmpty()){
29             //update unkown points‘ dist
30             for(PointInfo p:unknownSet){
31                 if(p.dist>nearest.dist+array[nearest.point][p.point]){
32                     p.prev_point=nearest.point;
33                     p.dist=nearest.dist+array[nearest.point][p.point];
34                 }
35             }
36             //find minimum dist point
37             nearest=new PointInfo(-1,-1,Integer.MAX_VALUE);
38             for(PointInfo p:unknownSet){
39                 if(p.dist<nearest.dist){
40                     nearest=p;
41                 }
42             }
43             //move from unknown to known
44             knownSet.add(nearest);
45             unknownSet.remove(nearest);
46         }
47
48         print(knownSet);
49     }
50     private static PointInfo getPoint(Set<PointInfo> pset,int index){
51         for(PointInfo p:pset){
52             if(p.point==index){
53                 return p;
54             }
55         }
56         return null;
57     }
58
59     private static void print(Set<PointInfo> knownSet){
60         for(int i=0;i<knownSet.size();i++){
61             int index=i;
62             log("node:"+(index+1)+",weight:"+getPoint(knownSet,index).dist);
63             while(index>=0){
64                 log(""+(index+1));
65                 index=getPoint(knownSet,index).prev_point;
66             }
67         }
68     }
69     public static int[][] makeUpGraph(){
70         int[][]array={
71                 {0,         15,         10,         Infinite,   Infinite,   1},
72                 {15,        0,          19,         33,         1,          Infinite},
73                 {10,        19,         0,          27,         Infinite,   Infinite},
74                 {Infinite,  33,         27,         0,          3,          45},
75                 {Infinite,  1,          Infinite,   3,          0,          1},
76                 {1,         Infinite,   Infinite,   45,         1,          0}
77
78         };
79         return array;
80     }
81     public static void log(String s){
82         System.out.println(s);
83     }
84     public static void main(String[]args){
85         doit_more_abstract(makeUpGraph());
86     }
87 }

Java 函数式实现版本

 1 import java.util.HashSet;
 2 import java.util.LinkedList;
 3 import java.util.Queue;
 4 import java.util.Set;
 5 public class Dijkstra {
 6     public static class PointInfo{
 7         public int point;
 8         public int prev_point;
 9         public int dist;
10         public PointInfo(int p,int pp,int d){
11             point=p;
12             prev_point=pp;
13             dist=d;
14         }
15     }
16 private static PointInfo getPoint(Set<PointInfo> pset,int index){
17         for(PointInfo p:pset){
18             if(p.point==index){
19                 return p;
20             }
21         }
22         return null;
23     }
24
25     private static void print(Set<PointInfo> knownSet){
26         for(int i=0;i<knownSet.size();i++){
27             int index=i;
28             log("node:"+(index+1)+",weight:"+getPoint(knownSet,index).dist);
29             while(index>=0){
30                 log(""+(index+1));
31                 index=getPoint(knownSet,index).prev_point;
32             }
33         }
34     }
35
36     public static void doit_functional_way(int[][]array){
37         int n=array[0].length;
38         Set<PointInfo> knownSet=new HashSet<PointInfo>();
39         Set<PointInfo> unknownSet=new HashSet<PointInfo>();
40         PointInfo source=new PointInfo(0,-1,0);
41         knownSet.add(source);
42         for(int p=1;p<n;p++){
43             unknownSet.add(new PointInfo(p,-1,Integer.MAX_VALUE));
44         }
45         PointInfo nearest=source;
46         Set<PointInfo> finalSet=iterate(knownSet, unknownSet, nearest, array);
47         print(finalSet);
48     }
49
50     private static Set<PointInfo> iterate(Set<PointInfo> knownSet,Set<PointInfo> unknownSet,PointInfo nearest,int[][]array){
51         if(unknownSet.isEmpty()){
52             return knownSet;
53         }
54         //update unkown points‘ dist
55         for(PointInfo p:unknownSet){
56             if(p.dist>nearest.dist+array[nearest.point][p.point]){
57                 p.prev_point=nearest.point;
58                 p.dist=nearest.dist+array[nearest.point][p.point];
59             }
60         }
61         //find minimum dist point
62         nearest=new PointInfo(-1,-1,Integer.MAX_VALUE);
63         for(PointInfo p:unknownSet){
64             if(p.dist<nearest.dist){
65                 nearest=p;
66             }
67         }
68         //move from unknown to known
69         knownSet.add(nearest);
70         unknownSet.remove(nearest);
71
72         return iterate(knownSet, unknownSet, nearest, array);
73     }
74
75     public static int[][] makeUpGraph(){
76         int[][]array={
77                 {0,         15,         10,         Infinite,   Infinite,   1},
78                 {15,        0,          19,         33,         1,          Infinite},
79                 {10,        19,         0,          27,         Infinite,   Infinite},
80                 {Infinite,  33,         27,         0,          3,          45},
81                 {Infinite,  1,          Infinite,   3,          0,          1},
82                 {1,         Infinite,   Infinite,   45,         1,          0}
83
84         };
85         return array;
86     }
87     public static void main(String[]args){
88         doit_functional_way(makeUpGraph());
89     }
90 }

如果你认真分析最短路径算法,会发现它实际包含了三个核心的概念

已知最短路径的点集合A(每个点的信息包括:点的名字、路径上前一个点的名字、路径长度)

未知最短路径的点集合B(每个点的信息包括:点的名字、路径上前一个点的名字prev_point、路径长度distance)

刚刚从集合B中选出的距离最小的点nearest_point。

执行过程

初始状态

集合A:仅包含源点

集合B:包含除源点外的所有点

nearest_point:源点

迭代的过程

根据nearest_point,更新集合B中每个点的prev_point、distance

从集合B中选出distance最小的点,作为新的nearest_point

将nearest_point从集合B移动到集合A中

结束条件:当集合B为空时,算法结束

个人认为,除了代码运行速度,比较C、Java、Java函数式三个版本implementation的最重要标准是:是否能够直接有力的体现出以上三个核心概念(集合A、集合B、nearest_point)和执行过程。大家如果有耐心读完三个版本的代码,会发现Java两个在这一点上明显比C版本提上了一个层次。

Java普通版本和Java函数式版本的差别在于While循环iterate递归函数iterate递归函数更加直观了表现出了“状态变换”。实际上,整个迭代过程就是前一个状态(集合A,集合B,nearest_point)=>后一个状态(集合A、集合B、nearest_point)的变换。

很多函数式语言的拥护者都说:函数式语言的优点是无副作用。我觉得这完全是人与亦云的胡扯。恰恰相反,在使用函数式语言写代码时,它带给我最大的障碍就是无法使用副作用。目前在我眼中,它的最美之处是function as first class object。其次则是对抽象概念和状态变换过程的优雅表达方式。

(我本来用Haskell作为函数式版本的代码示例,但考虑到很多同学大概对这种语言不熟悉,于是使用Java,大家可以看到,即使在imperative语言的环境中,依然可以运用函数式语言的思维方式写出优雅的代码。)

最短路径算法的命令式、函数式版本对比分析

时间: 2024-08-04 13:34:56

最短路径算法的命令式、函数式版本对比分析的相关文章

Kafka各版本对比分析

1    概述 目前我们部分系统还在使用Kafka0.8.2.2 的版本. 0.8.2.2版本发行于2014年10月28号,距今已经过去4年多的时间. 三年的时间,Kafka截至到(2018-02-28),已经累计发布了14个版本,最新版本为1.0.0,由此,0.8.2已经远远落后于Kafka的最新版本14个版本,很多新特性和功能比新版本有较大差距. 0.8.2.2到1.0.0版本中间有0.9.x,0.10.x,0.11.x,1.0.0等四个大本版本的更迭,集中讨论0.8存在的问题以及0.9.x

(转)netty、mina性能对比分析

转自: http://blog.csdn.net/mindfloating/article/details/8622930 流行 NIO Framework netty 和 mina 性能测评与分析 测试方法 采用 mina 和 netty 各实现一个 基于 nio 的EchoServer,测试在不同大小网络报文下的性能表现 测试环境 客户端-服务端: model name: Intel(R) Core(TM) i5-2320 CPU @ 3.00GHz cache size: 6144 KB

常用hash函数对比分析(一)

主要目标:寻找一个hash函数,高效的支持64位整数运算,使得在速度.空间等效率相对其它函数函数较高,以及内部运算时32位整数运算. 测试了"RSHash","JSHash","PJWHash","ELFHash","BKDRHash","SDBMHash","DJBHash","DEKHash","BPHash","

Android和Linux应用综合对比分析

公开发布的序言: 这篇文章是作于2012年7月12日,也就是自己刚从大学校园迈向工作岗位的时候遇到的第一个题目"请你针对我们公司目前的应用行业场景做一下调研:在终端做应用程序开发的平台是选择Linux好还是Android好"而写的. 在踏出校园之前,自己从来没有接触过安卓的开发领域(除了在2010年下半年买了一部分安卓的智能手机外).接到这个题目后,自己也没有退缩,硬着头皮接下来了,然后凭借自己在学校时候学的一点检索信息写学术论文的小功底,三天之内写下了这篇长达1万4千多字的调研报告,

近3年微软与谷歌的发展对比分析

     近3年微软与谷歌的发展对比分析   随着科技的快速发展,时代的不断进步,微软和谷歌凭借这不断的创新已然成为当今全球科技公司的领头羊.位列世界500强的微软是一个相当具有经济与科技实力的的公司,然而同样位列世界500强的谷歌凭借着家喻户晓的Google搜索成为了微软一个相当具有竞争力的科技大亨. 同为IT公司,微软和谷歌的比较如下: 一.发展历史 微软作为一个1975年成立的老牌公司,从一开始的为IBM提供文件系统和操作系统等软件,到现在业务中有各种操作系统编译器和解释器.网页浏览器等基

Go/Python/Erlang编程语言对比分析及示例

本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性,不过最主要的原因是这几个我比较熟悉. Go的很多语言特性借鉴与它的三个祖先:C,Pascal和CSP.Go的语法.数据类型.控制流等继承于C,Go的包.面对对象等思想来源于Pascal分支,而Go最大的语言特色,基于管道通信的协程并发模型,则借鉴于CSP分支. Go/Python/Erlang语言特性对比 如<编程语言与范式>一文所说,不管语言如何层出不穷

GitHub &amp; Bitbucket &amp; GitLab &amp; Coding 的对比分析

来源于:https://www.v2ex.com/t/313263 目前在代码托管和版本控制上的主流工具 — Git ,比较流行的服务有 Github . Bitbucket . GitLab . Coding ,他们各自有什么特点,个人使用者和开发团队又该如何选择? 在这篇文章中,我们以客观的态度,以问题作为出发点,介绍和比较 GitHub . Bitbucket . GitLab . Coding 在基本功能,开源与协作,免费与付费计划,企业解决方案,集成 flow.ci 等方面,让大家了解

最短路径算法整理(二)

本文是最短路径算法整理的第二篇,想阅读第一篇的朋友能够点击下面链接: http://blog.csdn.net/hjd_love_zzt/article/details/26739593 这一篇博客继续以一些OJ上的题目为载体,整理一下最短路径算法.会陆续的更新... 1.HDU 2544 题目与分析:这道题抽象一下,还是:"求a到b的最短路径"..所须要的基本条件是:点数.边数.起点.终点 下面给出floyd.dijkstra.bellmanford三种最短路径算法关于这道题的解法:

几个最短路径算法Floyd、Dijkstra、Bellman-Ford、SPFA的比较(转)

几大最短路径算法比较 几个最短路径算法的比较:Floyd        求多源.无负权边(此处错误?应该可以有负权边)的最短路.用矩阵记录图.时效性较差,时间复杂度O(V^3).       Floyd-Warshall算法(Floyd-Warshall algorithm)是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题. Floyd-Warshall算法的时间复杂度为O(N^3),空间复杂度为O(N^2). Floyd-Warshall的原理是动态规划:设Di,j