【问题标题】:Java: Using a Fibonacci Heap for Implementing Dijkstra's AlgorithmJava:使用斐波那契堆实现 Dijkstra 算法
【发布时间】:2013-03-01 19:11:22
【问题描述】:

这里是新人,但作为客人潜伏了很长一段时间:)

好的,所以我一直在尝试使用斐波那契堆(在 Java 中)来执行 Dijkstra 的最短路径算法。经过一番搜索,我偶然发现了两个代表斐波那契堆的现成实现。第一个实现非常漂亮,可以在here 找到。第二个实现,看起来不太优雅,是here

现在,这一切看起来都很好。但是,我想为我的 Dijkstra 算法版本使用其中一种实现,但我还没有运气。 Dijkstra在使用中的实现如下:

public void dijkstra(Vertex source) {
    {
        source.minDistance = 0.;
        PriorityQueue<Vertex> vertexQueue = new PriorityQueue<>();
        vertexQueue.add(source);

        while (!vertexQueue.isEmpty()) {
            Vertex u = vertexQueue.poll();

            // Visit each edge exiting u
            for (Edge e : u.adjacencies) {
                Vertex v = e.target;
                double weight = e.weight;
                double distanceThroughU = u.minDistance + weight;
                if (distanceThroughU < v.minDistance) {
                    vertexQueue.remove(v);
                    v.minDistance = distanceThroughU;
                    v.previous = u;
                    vertexQueue.add(v);
                }
            }
        }
    }
}

很明显,此实现使用基于 Java 的 PriorityQueue 类(我相信它基于二进制堆本身)。 我希望修改上面的代码,使其使用前面提到的斐波那契堆实现,而不是 Java 的 PriorityQueue。

我已经尝试了很多,但我就是不知道怎么做,尽管我确信它就像替换几行代码一样简单。

我希望我已经足够清楚了。这实际上是我在这些板上的第一篇文章。

任何帮助将不胜感激。

编辑:为了回应 cmets,我想我会用我的尝试场景之一来扩展我的帖子。

这里是使用前面链接的第二个斐波那契堆实现的上述 Dijkstra 方法的修改版本:

public static void computePathsFibonacciHeap(Node source) {
    {
        source.minDistance = 0.;
        FibonacciHeap myHeap = new FibonacciHeap();
        myHeap.insert(source, source.minDistance);

        while (!myHeap.isEmpty()) {
            Node u = myHeap.min();

            // Visit each edge exiting u
            for (Edge e : u.adjacencies) {
                Node v = e.target;
                double weight = e.weight;
                double distanceThroughU = u.minDistance + weight;
                if (distanceThroughU < v.minDistance) {
                    v.minDistance = distanceThroughU;
                    myHeap.decreaseKey(v, v.minDistance);
                    v.previous = u;
                }
            }
        }
    }
}

这几乎是直接从伪代码转换而来的(因此完全有可能我只是没有正确翻译它)。我得到的错误是“decreaseKey() 的值更大”。如果我尝试删除最小值,我会收到 NullPointerException。

我确定我做错了什么,我很想知道是什么。再次,这是使用第二个 FHeap 实现。我宁愿使用第一个实现来做到这一点(它看起来更加彻底/专业),但不幸的是我不知道如何去做。

【问题讨论】:

  • 向我们展示您尝试了什么以及失败的地方。我们会为此提供帮助。
  • 完成。谢谢你提醒我。

标签: java data-structures dijkstra fibonacci-heap


【解决方案1】:

我自己使用过这个算法。 decreaseKey 函数上方有一条注释,解释了该行为。

将指定元素的键降低到新的优先级。如果新的优先级大于旧的优先级,这个函数会抛出一个 非法参数异常。新的优先级必须是有限的双精度, 因此您不能将优先级设置为 NaN 或 +/- 无穷大。正在做 所以也会抛出 IllegalArgumentException。 假设条目属于这个堆。为了效率 原因,这在运行时不会被检查。

至于实现,我想你会想要使用 myHeap.dequeueMin().getValue() 而不是 myHeap.min()。不同之处在于,dequeueMin() 的工作方式类似于 poll(),并在找到它后将其从堆中删除。

而不是 myHeap.decreaseKey(v, v.minDistance),只需添加它,例如 myHeap.insert(v, v.minDistance)

【讨论】:

    【解决方案2】:

    您似乎缺少使用 Double.POSITIVE_INFINITY 将所有节点添加到堆中(距离为 0.0 的源节点除外)。这就是你有 NullPointerExceptions 的原因,它们根本不在堆中。

    我对几个开源斐波那契堆实现做了一些测试。你可以在这里找到测试本身:Experimenting-with-dijkstras-algorithm。这也是我的 Dijsktra 算法的优先队列版本:PriorityQueueDijkstra.java

    【讨论】:

      【解决方案3】:

      JDK 不提供斐波那契堆的实现。您必须创建自己的实现,或者您可以在这篇文章中找到一个:Fibonacci Heap

      之后你所要做的就是替换

      PriorityQueue<Vertex> vertexQueue = new PriorityQueue<>();
      

      通过

       FibonacciHeap<Vertex> vertexQueue = new FibonacciHeap<>();
      

      然后只需将调用更改为polladdremove 方法,并在您提供的实现中使用它们的等效方法。

      【讨论】:

      • 谢谢!尽管我确实在 OP 中提供了相同的实现。我的问题在于我无法准确弄清楚如何进行所有这些调整并让算法再次工作。我已经完全按照您之前的建议完成了,但没有运气。我已经更新了 OP 以反映这一点。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-13
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 2011-09-10
      • 1970-01-01
      相关资源
      最近更新 更多