簡體   English   中英

Java:使用斐波那契堆實現 Dijkstra 算法

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

新來的,但作為客人已經潛伏了很長一段時間:)

好的,所以我一直在嘗試使用斐波那契堆(在 Java 中)執行 Dijkstra 的最短路徑算法。 經過一番搜索,我偶然發現了兩個代表斐波那契堆的現成實現。 第一個實現做得相當漂亮,可以在這里找到。 第二種實現,看似不那么優雅,是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。

我已經嘗試了很多,但我就是不知道如何去做,盡管我確信它就像替換幾行代碼一樣簡單。

我希望我足夠清楚。 這實際上是我在這些板上的第一篇文章。

任何幫助將不勝感激。

編輯:為了回應評論,我想我會用我的嘗試場景之一來擴展我的帖子。

這是上述 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 實現。 我更願意使用第一個實現(它看起來更徹底/更專業),但不幸的是我無法弄清楚如何去做。

您似乎缺少使用 Double.POSITIVE_INFINITY 添加堆中的所有節點(距離為 0.0 的源節點除外)。 這就是為什么您有 NullPointerExceptions 的原因,它們根本不在堆中。

我對幾個開源的斐波那契堆實現做了一些測試。 您可以在此處找到測試本身: Experimenting-with-dijkstras-algorithm 這也是我的 Dijsktra 算法的優先隊列版本: PriorityQueueDijkstra.java

JDK 不提供斐波那契堆的實現。 您必須創建自己的實現,或者您可以在這篇文章中找到一個: Fibonacci Heap

之后你所要做的就是更換

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

經過

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

然后只需更改對poll的調用, addremove方法,並在您提供的實現中使用它們的等效方法。

我自己使用了這個算法。 reduceKey函數上方有一條注釋,解釋了該行為。

將指定元素的鍵降低到新的優先級。 如果新優先級大於舊優先級,則此函數將引發 IllegalArgumentException。 新的優先級必須是有限雙精度值,因此您不能將優先級設置為 NaN 或 +/- 無窮大。 這樣做也會引發 IllegalArgumentException。 假定該條目屬於該堆。 出於效率原因,這不會在運行時檢查。

至於實現,我想你會想要使用myHeap.dequeueMin().getValue()而不是myHeap.min() 不同之處在於, dequeueMin() 的工作方式與poll()類似,並在找到它后將其從堆中刪除。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM