使用现有的Fibonacci堆Java实现与Dijkstra的最短路径Java实现

时间:2016-02-29 20:18:34

标签: java algorithm dijkstra shortest-path fibonacci-heap

使用java编程语言,我试图在具有正边缘成本的图形上实现最有效的最短路径算法。据我所知,这将是Dijkstra的算法,其中Fibonacci Heap作为优先级队列。我借用了Keith Schwarz的以下Fibonacci Heap实现,如链接中所述。 http://keithschwarz.com/interesting/code/?dir=fibonacci-heap

在我的代码中,我还修改了这个问题中提出的dijkstra算法实现,

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

根据我的实施,我的更新后的dijkstra

public static void SPFibonacciHeap() {
    {

        FibonacciHeap<Node> myHeap = new FibonacciHeap<Node>();

        //adding all nodes to the PQ (heap)
        for(int i=0; i<nodeList.size(); i++)
                    myHeap.enqueue(nodeList.get(i), nodeList.get(i).d);

        while (!myHeap.isEmpty()) {

            //deque the minimum (first iteration will be the source)
            Entry<Node> u = myHeap.dequeueMin();


            // Visit each edge connected from u
            for (AdjacentNode a : u.getValue().adjacents) {

                //getting the adjacent node
                Node v = a.node;
                Entry<Node> vEntry = new Entry<Node>(v,v.d);//WRONG

                //getting the edge weight
                double weight = a.cost;

                double distanceThroughU = u.getValue().d + weight;
                if (distanceThroughU < v.d) {
                    v.d = distanceThroughU;
                    myHeap.decreaseKey(vEntry, v.d); //SHOWS ERROR
                    v.parent = u.getValue();
                }
            }
        }
    }
}

这是我的Node和AdjacentNode类,

class Node{

    Double [] label;
    double d; //node cost
    ArrayList<AdjacentNode> adjacents;
    Node parent;

    public Node(Double[] label, double d,ArrayList<AdjacentNode> adjacents)
    {
        this.label= label;
        this.d=d;
        this.adjacents=adjacents;
        parent=null;

    }




}


class AdjacentNode
{
    Node node;
    double cost;

    public AdjacentNode(Node node, double cost)
    {
        this.node= node;
        this.cost=cost;
    }
}

一切顺利,直到我想减少以下行中的密钥,

myHeap.decreaseKey(vEntry, v.d); 

我面临的问题是vEntry应该是堆中已存在的节点。但是,我无法从堆中检索此节点,因为我可以考虑检索相邻节点v的唯一方法是使用节点u中的邻接列表。但是,我错误地将其表示为以下行中的新条目节点,

Entry<Node> vEntry = new Entry<Node>(v,v.d);

然而,这会创建一个新的Entry来保存我正在寻找的节点,而不是存在于我正在寻找的节点的堆中的条目。这会导致Null指针异常,如预期的那样。

我无法弄清楚这个问题的解决方案。获取与给定节点条目相邻的节点条目似乎不可能用于此堆实现吗?有人可以帮忙吗?谢谢。

1 个答案:

答案 0 :(得分:1)

所以......这是我的代码。 :-)我想我可能会帮到这里。

如果你注意到,enqueue方法返回一个Entry<T>,表示Fibonacci堆中与你刚刚入队的对象相对应的内部条目。目的是,当你将某些东西排入Fibonacci堆时,你将保存Entry<T>,然后你可以回到某个地方,以便以后可以使用它。实际上我的网站上还有an implementation of Dijkstra's algorithm。我做这项工作的方式是将第二个Map从节点存储到Entry个对象,这样当我需要调用decreaseKey时,我可以查找Entry对应的到给定节点,然后将其传递给decreaseKey

作为一个单挑,虽然Dijkstra的算法与Fibonacci堆理论理论比使用普通二进制堆,在实践中更快,但它往往是一个因为Fibonacci堆上的常数因子要高得多,所以要慢得多。这是由于许多因素(大量指针玩杂耍,许多链接结构与地方性差等),所以如果你的目标是获得最快的挂钟速度,你可能只想使用一个普通的老式二进制堆。即使你确实想要使用Fibonacci堆,你也可以尝试优化我发布的实现 - 我写的是正确性和清晰度而不是原始效率。