Java Priority Queue reordering when editing elements

后端 未结 6 1122
陌清茗
陌清茗 2020-11-29 06:23

I\'m trying to implement Dijkstra\'s algorithm for finding shortest paths using a priority queue. In each step of the algorithm, I remove the vertex with the shortest distan

6条回答
  •  挽巷
    挽巷 (楼主)
    2020-11-29 07:10

    As you discovered, a priority queue does not resort all elements whenever an element is added or removed. Doing that would be too expensive (remember the n log n lower bound for comparison sort), while any reasonable priority queue implementation (including PriorityQueue) promises to add/remove nodes in O(log n).

    In fact, it doesn't sort its elements at all (that's why its iterator can not promise to iterate elements in sorted order).

    PriorityQueue does not offer an api to inform it about a changed node, as that would require it to provide efficient node lookup, which its underlying algorithm does not support. Implementing a priority queue that does is quite involved. The Wikipedia article on PriorityQueues might be a good starting point for reading about that. I am not certain such an implementation would be faster, though.

    A straightforward idea is to remove and then add the changed node. Do not do that as remove() takes O(n). Instead, insert another entry for the same node into the PriorityQueue, and ignore duplicates when polling the queue, i.e. do something like:

    PriorityQueue queue = new PriorityQueue();
    
    void findShortestPath(Node start) {
        start.distance = 0;
        queue.addAll(start.steps());
    
        Step step;
        while ((step = queue.poll()) != null) {
            Node node = step.target;
            if (!node.reached) {
                node.reached = true;
                node.distance = step.distance;
                queue.addAll(node.steps());
            }
        }
    
    }
    

    Edit: It is not advisable to change the priorities of elements in the PQ, hence the need to insert Steps instead of Nodes.

提交回复
热议问题