10.2 单源加权Dijkstra算法

  加权图的最短路径算法发明者是Edsger Dijkstra,一个荷兰的计算机科学家。我之前写的关于栈的文章里介绍过这个科学家,因为双栈算法也是他发明的。这个算法的核心是两个集合。第一个集合是路径长度已经确定的集合。加权图的最短路径,计算的是到每个点的最短路径。所以它的输入参数只有起点。它的核心思想超级简单啊。对于N的点的图来说,起点为S。那么距离最短的点肯定是S本身。这个算法维护了一个数组,叫做距离数组。数组下标对应点的索引。
  初始化时距离数组里只有S本身的距离是0。其余点都是正无穷。
  第一轮
  遍历S的所有边,将他们到S的距离更新为边的权重。
  第二轮才是有意思的地方。
  找到距离S最近的点U
  遍历U的所有边,以V代替,将S到U的距离 d [ u ] d[u] d[u]加上U到V的距离 w ( u , v ) w(u,v) w(u,v)
  这个距离如果小于S到V的距离 d [ v ] d[v] d[v],那么修正S到V的距离为新距离,也就是修正距离数组。
  核心算法就是不断修正这个距离,最后计算出S到各个点的最短路径。我用一张图表示一下:

在这里插入图片描述

  为了避免成环,把所有的U放入一个哈希集合中,每次选择U时,都选择哈希集合中不存在的,或者说是已经计算过的。
  这个算法实际上是遍历了所有的边,并且修正了所有的距离来计算出加权图的最短路径。代码如下:

/**
 * 最短路径
 * @return 列表
 */
public int[] shortestPath(int source) {
    // 首先一个set T
    final HashSet<Integer> t = new HashSet<>();
    // cost是一个数组啊
    int[] cost = new int[vertices.length];
    Arrays.fill(cost, Integer.MAX_VALUE);
    cost[source] = 0;
    int[] parent = new int[vertices.length];
    parent[source] = -1;
    while (t.size() < vertices.length) {
        // u 要是最短的 u not in t with the smallest cost
        int u = findU(t, cost);
        t.add(u);
        for(WeightedEdge edge : edges[u]) {
            final int v = edge.getTo();
            if (cost[v] > cost[u] + edge.getWeight()) {
                cost[v] = cost[u] + edge.getWeight();
                parent[v] = u;
            }
        }
    }
    return parent;
}

private int findU(HashSet<Integer> t, int[] cost) {
    final ArrayList<Integer> temp = new ArrayList<>();
    for (int i = 0; i < vertices.length; i++) {
        if (!t.contains(i)) {
            temp.add(i);
        }
    }
    int u = temp.get(0);
    // 找出最小的索引
    for (int i = 1; i < temp.size(); i++) {
        if (cost[temp.get(i)] < cost[u]) {
            u = temp.get(i);
        }
    }
    return u;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒过来摸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值