迪杰斯特算法 Scala 实现


迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。
迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。(参考百度)
先看图(图片参考 博客http://www.cnblogs.com/skywang12345/p/3711516.html)

 

先看10遍图,仔细看(要不你花的时间会不止2小时)

 

看完图到最下面看算法思想,先不要看代码
import scala.collection.mutable
import scala.runtime.StringFormat

/**
  * Created by root on 2017/2/9 0009.
  */
object ShortDis {
  def main(args:Array[String]): Unit ={
    //step1:构建方形矩阵
    val matrix = Array.ofDim[Int](7,7)
    //略去添加49个数据,创建一个map集合存放一直的两点距离,两次for循环生成二维数组,给matrix元素赋值
    val map = new mutable.HashMap[String,Int]()
    map.put("0-1",12)
    map.put("0-5",16)
    map.put("0-6",14)
    map.put("1-0",12)
    map.put("1-5",7)
    map.put("1-2",10)
    map.put("2-1",10)
    map.put("2-5",6)
    map.put("2-4",5)
    map.put("2-3",3)
    map.put("3-4",4)
    map.put("3-2",3)
    map.put("4-2",5)
    map.put("4-5",2)
    map.put("4-3",4)
    map.put("4-6",8)
    map.put("5-1",7)
    map.put("5-2",6)
    map.put("5-0",16)
    map.put("5-4",2)
    map.put("5-6",9)
    map.put("6-0",14)
    map.put("6-5",9)
    map.put("6-4",8)

    val map2 = new mutable.HashMap[Int,String]()
    map2.put(0,"A")
    map2.put(1,"B")
    map2.put(2,"C")
    map2.put(3,"D")
    map2.put(4,"E")
    map2.put(5,"F")
    map2.put(6,"G")

    //------------创建矩阵和点的映射关系------------
    for(i<- 0 to 6){
      for(j<- 0 to 6){
        val key = new StringBuilder().append(i).append("-").append(j)

        if(i==j){   //点aa,bb,cc 等距离是0
          matrix(i)(j)=0
        }else if(map.contains(key.toString())){  //判断两点之间是有有连接
        val value: Array[Int] = map.get(key.toString()).toArray  //暂时不知道Option[int] 直接转化为Int
          matrix(i)(j) =value(0)
        }else{
          matrix(i)(j)=65535   //两点之间没有直连就是无穷大
        }
      }
    }

    println("------------打印矩阵和点的映射关系------------")
    for(i<- 0 to 6){
      //打印矩阵
      for(j<- 0 to 6) print(new StringFormat(matrix(i)(j)).formatted("%6s"))
      println() //换行
    }
    println("------------分割线------------")

    val flag =new Array[Boolean](7)  //创建标记数组,初始都为false
    var pre = 3           //设置起点变量pre(D为起点,下标对应表参考map2)
    flag(pre)=true            //将起点标记为true
    val DIS = new Array[Int](7)  //创建数组DIS,用于存放最短距离,初始为0
    println("起点为:"+map2.get(pre) +" dis:"+DIS(pre))   //打印起点

    var minDis=65535    //到集合DIS的最短距离
    var minIndex = 0     //最短邻居下标

    while(flag.contains(false)){  //循环终止条件,当标签集合中不存在false时终止循环
      minDis=65535

      for(k <- 0 to 6){
        //遍历集合Other
        if(!flag(k)){  //未确定最短距离的点的下标为K
          for(m <- 0 to 6){
            //遍历集合DIS
            if(flag(m)){ //已确定最短距离的点的下标m
              if( minDis>(matrix(k)(m)+DIS(m))) {minDis=matrix(k)(m)+DIS(m);pre=k} //将最短距离赋值给minDis
            }
          }
        }
      }

      flag(pre) = true  //将下一个前驱点标记为true
      DIS(pre) = minDis  //将最短邻居点到起点的距离存入DIS集合
      println("距离起点D最短路径点:"+map2.get(pre) +" 最短距离:"+DIS(pre))
    }
//    for(i<- 0 to 6) println(i + ":" + DIS(i) + flag(i))
  }
}

 

 

 运行结果如下:

 

楼主走了很多弯路,看到其他博主写的理论很好看,图也很好,就是代码太难懂,以至于自己无从下手,写着写着发现,根本就没什么所谓的前驱点,什么最近相邻点
先思考如下问题:

1.打印整数集合A和整数集合B元素两两相加,怎么用代码实现
2.怎么求出整数集合A和整数集合B元素两两相加的最小值?

开胃菜吃完了继续下面:
通过看图,我们会发现其实就是一个集合A到集合B的最短距离点C,然后A集合remove点C,B集合add点C;
一直重复,直到集合A全部取完

经典的一句总结:迪杰斯特算法就是未知路径点集合到已知最短路径点集合的笛卡尔和的最小值;(是和不是积,你没看错)
由于对scala 的api不熟,后期再做代码改进








posted @ 2017-02-11 00:10  瓦肯船长  阅读(727)  评论(0)    收藏  举报