码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-06-28 10:13:49      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   java   color   get   

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

bubuko.com,布布扣
  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 }
View Code

Java普通版本

bubuko.com,布布扣
 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 }
View Code

Java 函数式实现版本

bubuko.com,布布扣
 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 }
View Code

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

    已知最短路径的点集合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语言的环境中,依然可以运用函数式语言的思维方式写出优雅的代码。)

最短路径算法的命令式、函数式版本对比分析,布布扣,bubuko.com

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

标签:style   blog   http   java   color   get   

原文地址:http://www.cnblogs.com/linghuaichong/p/3810932.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!