算法:图-迪特斯克拉算法

算法:图-迪特斯克拉算法

图算法

图,包含定点和边,就是计算起始定点到目标定点的最短开销。(举例:在游戏中,常运用于计算 rpc 到英雄的最短距离。)
之前看了网上别人写的图算法,在这里,从原理到实现做一个详细解读

计算过程

迪特斯克拉算法
此处举例的图,结构如下:
一共6个顶点,a1是起始顶点,a6是终点

30
60
300
3
25
70
15
10
a1
a3
a4
a6
a2
a5

注意:后面的讲解会用到<当前顶点>这个角色,可以想象为当前选中的顶点,对应的,还有<上一个顶点>,<下一个顶点>

  1. 先初始化所有的顶点开销为无穷大。初始化<当前顶点>为第一个顶点
30
60
300
3
25
70
15
10
a1
a3
a4
a6
a2
a5
  1. 计算<当前顶点>到<下一个顶点>的最短开销。
30
60
300
3
25
70
15
10
a1
a3
a4
a6
a2
a5

结果:<当前顶点>到a3的开销最小
3. <当前顶点>移动到<下一个顶点>位置(最短开销的顶点)。

30
60
300
3
25
70
15
10
a1
a3
a4
a6
a2
a5
  1. 比较 :第一个顶点直接到<下一个顶点>的距离 a,
30
60
300
3
25
70
15
10
a1
a3
a4
a6
a2
a5

第一个顶点到<当前顶点>+<当前顶点>到<下一个顶点>的最短距离 b。

30
60
300
3
25
70
15
10
a1
a3
a4
a6
a2
a5

如果 a<b:
路径:路径设定为a,也就是第一个顶点直接到下一个顶点,也就是a1–>a4
否则:路径设定为b,也就是从第一个顶点->当前顶点->下一个顶点
现在,a=60,b=30+25 ,所以路径暂时设定为b
6. 重复2-4过程,直到当前顶点移动到终点

编码

将图元素用代码定义出来
1,顶点
已经作过 “当前顶点“ 这个角色的点,为true,否则为null
temp = 【true,null,null,null,null,null】
顶点用数组的 index 定义。顶点1 就是 temp 的 index=0

2,边
边,就是开销值。如果没有连接,则开销为无穷大。

3,图
用邻接矩阵表示

Integer infinity =  Integer.MAX_VALUE;  //用 infinity 代表无穷大
 Integer[][] paraGraph=new Integer[][]{
         //从a1定点出发,到各定点的开销 
         {0,       infinity,30,60,      infinity,    300},
         //从a2顶点出发,到各个顶点的开销
         {infinity,      0,  3,infinity,infinity,infinity},
         //从a3顶点出发,到各个顶点的开销
         {infinity,infinity, 0,      25,infinity,infinity},
         //从a4顶点出发,到各个顶点的开销
         {infinity,infinity,infinity, 0,infinity,70},
         //从a5顶点出发,到各个顶点的开销
         {infinity,infinity,infinity, 15,      0,10},
         //从a6顶点出发,到各个顶点的开销
         {infinity,infinity,infinity,infinity,infinity,0}
 };

4,第一个顶点到终点的距离开销。

// distance代表从第一个点到其他点的开销之和。例如 distance[2] 代表从第一个点,也就是 temp[0] 到 temp[2] 的开销的和(也是最小开销),其中,从第一个点到最后一个点,不经过的点的开销为无穷大
Integer[] distance=new Integer[6]; 
// 用第一个点到其他点的直接的开销,初始化distance。没有连接的用无穷大初始化
for(Integer i=0;i<6;i++)
    distance[i]=paraGraph[0][i];

开始编码:

  1. 计算第一个顶点到当前顶点的最短开销。
Integer min=Integer.MAX_VALUE; //第一个顶点到当前顶点最小的开销
Integer index=-1; //当前顶点所在的位置

// 遍历第一个顶点和其他顶点直接的开销,选出最小开销,赋值给min
for(Integer i=0;i<distance.length;i++){
    // 选一个点为当前顶点
    // 忽略第一个顶点,忽略当过 “当前顶点” 的顶点
    if(temp[i] == Boolean.TRUE)
        continue;
    else{
        //获取第一个点到当前顶点的最短距离,以及当前顶点的index
        if(distance[i]<min){
            index=i;
            min=distance[i];
        }
    }
}

  1. 标记此顶点已经当过 “当前顶点”这个角色
temp[index]=Boolean.TRUE;

比较 :第一个顶点直接到下一个顶点的距离 a,第一个顶点到当前顶点+当前顶点到下一个顶点的最短距离 b

for(Integer i=0;i<paraGraph.length;i++){
      //如果当前顶点和另外一个顶点有连接
      if(paraGraph[index][i]!=Integer.MAX_VALUE){
          //比对第一个顶点到下一个节点的开销,是否小于(第一个顶点到当前顶点的最小开销+当前顶点到下一个顶点的开销)
          if(distance[i] < min+paraGraph[index][i]){
              distance[i] = distance[i]; // 如果小,则直接使用第一个点到下一个点的开销
          }else{
              distance[i]  =  min + paraGraph[index][i]; // 否则,使用第一个点到当前点,然后从当前点再到下一个点的开销
          }
      }
  }

重复上述步骤……
最终代码如下:

public class minDistance {
    public static void main(String[] args) {
        //这里我们将无穷大定义为int类型最大值 2^32-1  2147483647
        Integer infinity =  Integer.MAX_VALUE;
        //构建图,用邻接矩阵作为图的数据结构,该地图是边的数组
        Integer[][] paraGraph=new Integer[][]{
                //从a1定点出发,到各定点的开销 从a1开始
                {0,       infinity,30,60,      infinity,    300},
                //从a2顶点出发,到各个顶点的开销 从a1开始
                {infinity,      0,  3,infinity,infinity,infinity},
                //从a3顶点出发,到各个顶点的开销 从a1开始
                {infinity,infinity, 0,      25,infinity,infinity},
                //从a4顶点出发,到各个顶点的开销 从a1开始
                {infinity,infinity,infinity, 0,infinity,70},
                //从a5顶点出发,到各个顶点的开销 从a1开始
                {infinity,infinity,infinity, 15,      0,10},
                //从a6顶点出发,到各个顶点的开销 从a1开始
                {infinity,infinity,infinity,infinity,infinity,0}
        };
//      distance代表从第一个点到其他点的开销之和。例如 distance[2] 代表从第一个点,也就是 temp[0] 到 temp[2] 的开销的和(也是最小开销),其中,从第一个点到最后一个点,不经过的点的开销为无穷大
        Integer[] distance=new Integer[6];
        for(Integer i=0;i<6;i++)
            distance[i]=paraGraph[0][i];

        Boolean[] temp=new Boolean[6];//temp集合

        minDistance(paraGraph, distance, temp);

    }
    public static void  minDistance(Integer[][] paraGraph,Integer[] distance,Boolean[] temp){
        temp[0]=true; //如果对应位置的定点计算过,则temp[i]设定为true

        while(true){//外层循环
            Integer min=Integer.MAX_VALUE; //当前顶点最小的开销
            Integer index=-1; //当前顶点所在的位置

            //内层循环:比对每个顶点和其他顶点之间的距离,获取最小距离
            for(Integer i=0;i<distance.length;i++){
                //比对定点是否已经计算过,开始的顶点忽略,从第二个顶点开始
                if(temp[i] == Boolean.TRUE)
                    continue;//不包括集合temp中的顶点 已经包括了就继续循环,不在加入范围
                else{
                    System.out.println(i);
                    //获取到下一个顶点的最短距离,以及下一个顶点的index
                    if(distance[i]<min){
                        index=i;
                        min=distance[i];
                    }
                }
            }

            System.out.println("index "+index);
            minDistance.<Integer>printTostring(distance);

            if(index==-1) break;//index移动到最后的顶点,跳出循环

            // 标记此顶点已经当过 “当前顶点”这个角色
            temp[index]=Boolean.TRUE;
            for(Integer i=0;i<paraGraph.length;i++){
                //如果当前顶点和另外一个顶点有链接
                if(paraGraph[index][i]!=Integer.MAX_VALUE){
                    //比对第一个顶点到其他顶点的开销,是否小于(第一个顶点到当前顶点的最小开销+当前顶点到下一个顶点的开销)
                    if(distance[i] < min+paraGraph[index][i]){
                        distance[i] = distance[i]; // 如果小,则直接使用第一个点到下一个点的开销
                    }else{
                        distance[i]  =  min + paraGraph[index][i]; // 否则,使用第一个点到当前点,然后从当前点再到下一个点
                    }
                }
            }
        }
    }
//    用于打印数组的方法
    public static <T> void printTostring(T[] parent){
        for (T son:parent) {
            System.out.print(son+" ");
        }
        System.out.println("");
    }

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值