Java:使用Fibonacci堆实现Dijkstra算法

时间:2013-03-13 17:26:17

标签: java data-structures dijkstra fibonacci-heap

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

好的,所以我一直在尝试使用Fibonacci堆(在Java中)做Dijkstra的最短路径算法。经过一些搜索,我设法偶然发现了两个代表Fibonacci堆的现成实现。第一个实现相当精美,可以找到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类(我认为它基于二进制堆本身)。 我希望修改上面的代码,以便它使用前面提到的Fibonacci堆实现,而不是Java的PriorityQueue。

我已经尝试了很多,但我无法弄清楚如何做到这一点,虽然我确信它就像更换几行代码一样简单。

我希望我足够清楚。这是我在这些主板上的第一篇文章。

非常感谢任何帮助。

编辑: 为了回应评论,我想我会用我的一个尝试场景扩展我的帖子。

以下是使用之前链接的第二个Fibonacci堆实现的上述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实现。我宁愿使用第一个实现(它只是看起来更彻底/专业),但遗憾的是我无法弄清楚如何。

3 个答案:

答案 0 :(得分:0)

JDK没有提供Fibonacci堆的实现。您必须创建自己的实现,或者在此帖子中找到一个:Fibonacci Heap

之后您需要更换

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

通过

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

然后,只需将调用更改为polladdremove方法及其提供的实现中的等效方法。

答案 1 :(得分:0)

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

我对几个开源的Fibonacci Heap实现进行了一些测试。您可以在此处找到测试本身:Experimenting-with-dijkstras-algorithm。这也是我的Dijsktra算法的优先级队列版本:PriorityQueueDijkstra.java

答案 2 :(得分:0)

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

  

将指定元素的键减少到新优先级。如果新优先级大于旧优先级,则此函数抛出一个         IllegalArgumentException异常。新的优先级必须是有限的双倍,        所以你不能将优先级设置为NaN或+/-无穷大。干         所以也抛出IllegalArgumentException。              假设该条目属于此堆。为了效率         原因,这不是在运行时检查。

至于实现方式,我认为您希望使用 myHeap.dequeueMin()。getValue()而不是 myHeap.min()。区别在于, dequeueMin()的工作方式与 poll()类似,并在找到它后将其从堆中删除。

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