简体   繁体   English

Java:使用斐波那契堆实现 Dijkstra 算法

[英]Java: Using a Fibonacci Heap for Implementing Dijkstra's Algorithm

New here, but have been lurking as a guest for quite some time :)新来的,但作为客人已经潜伏了很长一段时间:)

Okay, so I've been trying to do Dijkstra's shortest path algorithm using a Fibonacci heap (in Java).好的,所以我一直在尝试使用斐波那契堆(在 Java 中)执行 Dijkstra 的最短路径算法。 After some search, I managed to stumble across two ready-made implementations representing a Fibonacci heap.经过一番搜索,我偶然发现了两个代表斐波那契堆的现成实现。 The first implementation is rather beautifully well done and can be found here .第一个实现做得相当漂亮,可以在这里找到。 The second implementation, seemingly less elegant, is here .第二种实现,看似不那么优雅,是here

Now, this all looks nice and well.现在,这一切看起来都很好。 However, I want to use one of those implementations for my version of Dijkstra's algorithm but I have yet to have any luck with that.但是,我想为我的 Dijkstra 算法版本使用这些实现之一,但我还没有运气。 The implementation of Dijkstra's in use is as follows: 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);
                }
            }
        }
    }
}

As is clear, this implementation uses the Java-based PriorityQueue class (which I believe is based on a binary heap itself).很明显,这个实现使用了基于 Java 的 PriorityQueue 类(我相信它基于二进制堆本身)。 I wish to modify the above code so it uses either of the aforementioned Fibonacci heap implementations instead of Java's PriorityQueue.我希望修改上面的代码,以便它使用上述斐波那契堆实现中的任何一个,而不是 Java 的 PriorityQueue。

I have tried a lot but I just can't figure out how to do it, although I'm sure it's as simple as replacing a few lines of code.我已经尝试了很多,但我就是不知道如何去做,尽管我确信它就像替换几行代码一样简单。

I hope I'm clear enough.我希望我足够清楚。 This is literally my first post on these boards.这实际上是我在这些板上的第一篇文章。

Any help would be greatly appreciated.任何帮助将不胜感激。

EDIT: In response to comments, I figured I would expand my post with one of my attempt scenarios.编辑:为了回应评论,我想我会用我的尝试场景之一来扩展我的帖子。

Here is a modified version of the above Dijkstra method using the second Fibonacci heap implementation linked earlier:这是上述 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;
                }
            }
        }
    }
}

This is pretty much converted directly from pseudocode (thus it's entirely possible that I just didn't translate it right).这几乎是直接从伪代码转换而来的(因此完全有可能我只是没有正确翻译它)。 The error I get says "decreaseKey() got a larger value".我得到的错误是“decreaseKey() 得到了更大的值”。 If I try to remove the minimum, I get a NullPointerException.如果我尝试删除最小值,则会收到 NullPointerException。

I'm sure I'm doing something wrong, and I'd love to know what it is.我确定我做错了什么,我很想知道它是什么。 Once again, this is using the second FHeap implementation.再一次,这是使用第二个 FHeap 实现。 I would have preferred to do it using the first implementation (it just looks a lot more thorough/professional) but I unfortunately couldn't figure out how to.我更愿意使用第一个实现(它看起来更彻底/更专业),但不幸的是我无法弄清楚如何去做。

It seems you are missing to add all the nodes the your heap with Double.POSITIVE_INFINITY (except the source node with 0.0 distance).您似乎缺少使用 Double.POSITIVE_INFINITY 添加堆中的所有节点(距离为 0.0 的源节点除外)。 That's why you are having NullPointerExceptions, they are simply not in the heap.这就是为什么您有 NullPointerExceptions 的原因,它们根本不在堆中。

I made some test on several open-source Fibonacci Heap implementation.我对几个开源的斐波那契堆实现做了一些测试。 You can find the test itself here: Experimenting-with-dijkstras-algorithm .您可以在此处找到测试本身: Experimenting-with-dijkstras-algorithm Also this is my Priority Queue version of the Dijsktra's algorithm: PriorityQueueDijkstra.java这也是我的 Dijsktra 算法的优先队列版本: PriorityQueueDijkstra.java

The JDK does not provide an implementation of the Fibonacci Heap. JDK 不提供斐波那契堆的实现。 You will have to create your own implementation, or you can find one in this post: Fibonacci Heap您必须创建自己的实现,或者您可以在这篇文章中找到一个: Fibonacci Heap

All you have to afterwards is replacing之后你所要做的就是更换

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

by经过

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

Then simply change the calls to the poll , add and remove methods with their equivalent in your provided implementation.然后只需更改对poll的调用, addremove方法,并在您提供的实现中使用它们的等效方法。

I worked with this algorithm myself.我自己使用了这个算法。 There is a comment above the decreaseKey function which explains the behaviour.reduceKey函数上方有一条注释,解释了该行为。

Decreases the key of the specified element to the new priority.将指定元素的键降低到新的优先级。 If the new priority is greater than the old priority, this function throws an IllegalArgumentException.如果新优先级大于旧优先级,则此函数将引发 IllegalArgumentException。 The new priority must be a finite double, so you cannot set the priority to be NaN, or +/- infinity.新的优先级必须是有限双精度值,因此您不能将优先级设置为 NaN 或 +/- 无穷大。 Doing so also throws an IllegalArgumentException.这样做也会引发 IllegalArgumentException。 It is assumed that the entry belongs in this heap.假定该条目属于该堆。 For efficiency reasons, this is not checked at runtime.出于效率原因,这不会在运行时检查。

As for the implementation, I think you would want to use myHeap.dequeueMin().getValue() instead of myHeap.min() .至于实现,我想你会想要使用myHeap.dequeueMin().getValue()而不是myHeap.min() The difference is, dequeueMin() works like poll() and removes it from the heap after finding it.不同之处在于, dequeueMin() 的工作方式与poll()类似,并在找到它后将其从堆中删除。

And instead of myHeap.decreaseKey(v, v.minDistance) , simply add it, like myHeap.insert(v, v.minDistance) .而不是myHeap.decreaseKey(v, v.minDistance) ,只需添加它,如myHeap.insert(v, v.minDistance)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM