How to iterate over a PriorityQueue?

Deadly 提交于 2019-11-26 16:05:50

问题


for (Event e : pq)

doesn't iterate in the priority order.

while(!pq.isEmpty()){
  Event e = pq.poll();
}

This works but empties the queue.


回答1:


From the Javadocs:

The Iterator provided in method iterator() is not guaranteed to traverse the elements of the PriorityQueue in any particular order. If you need ordered traversal, consider using Arrays.sort(pq.toArray()).

There are probably other equivalent mechanisms.




回答2:


You can't traverse a Priority Queue in that order because of the underlying implementation (I think it's min-heap in Java).

It's not a sorted array, so that you can just go from one element to the one with the lesser priority.

Peeking (read the top element heap in the heap) is constant time O(1) because it looks at the smallest element.

To get the second next one you must dequeue the smallest top element, that's how it works.
Dequeing (re-heapify = O(log n) time) isn't just a matter of taking that element out, the underlying structure rearranges itself in order to bring the element with the least priority first.

Also, to go through the entire priority queue to read all items in the sorted order, it is an O(n log(n)) operation.
So you may as well just grab all the elements in the queue and sort them (also O(n log (n)) )and then you can go through them as you wish. The only disadvantage is that you're holding an extra-copy of the queue.

Nonetheless, if you need to traverse the data in this way a priority queue may not be the right data structure for your needs.




回答3:


A heap based priority queue only guarantees that the first element is the highest/lowest. There is no cheap (i.e. O(n)) way to get the elements in sorted form.

If you need to do this often, consider using a structure that maintains the elements in sorted form. For example, use java.util.TreeSet, and use either pollFirst() or pollLast() in place of peek() / poll()




回答4:


Previous posters said everything but noone gave full working example (other than copying pq), so here it is:

Event[] events = pq.toArray(new Event[pq.size()]);
Arrays.sort(events, pq.comparator());
for (Event e : events) {
    System.out.println(e);
}



回答5:


Recently, I had same problem. I wanted to use some particular object from the priority queue and then keep remaining elements preserved.

1) I created a newPriorityQueue. 2) Used Iterator to parse every element in oldQueue 3) used oldQueue.poll() method to retrieve the element 4) insert the element 3) to newPriorityQueue if not used.

 Queue<String> newQueue = new PriorityQueue<String>(); 
    // Assuming that oldQueue have some data in it.

    Iterator<String> itr = oldQueue.iterator();
    while(itr.hasNext()){
        String str = oldQueue.poll();
        // do some processing with str
        if(strNotUsed){
            newQueue.offer(str);
        }
    }

In the end, oldQueue will be empty. @ Others : - please suggest a better way if I can do the same thing. I can not use the iterator as it does not return elements in the correct order.




回答6:


You can make a copy of the queue and poll in a loop, in this example pq is the original priority queue:

PriorityQueue<Your_class> pqCopy = new PriorityQueue<Your_class>(pq);
while(!pqCopy.isEmpty()){
    Your_Class obj = pqCopy.poll();
    // obj is the next ordered item in the queue
    .....
}



回答7:


So taking the priorityQueue in a List and then sorting it is a good option as mentioned above. Here are some details why the iterator gives unexpected results:

The iterator does not return elements in the correct order because it prints from the underlying data structure (similar to ArrayList). The ArrayList has data stored in it in the same way the data is stored in an Array implementation of BinaryHeap. For example:

PriorityQueue<Integer> pq = new PriorityQueue<>();
ArrayList<Integer> test = new ArrayList(Arrays.asList(6,12,7,9,2));
test.forEach(x -> pq.add(x)); 
System.out.println("Priority Queue:- "+pq); [2, 6, 7, 12, 9]

where childOf(i) is 2*i+1 and 2*i+2 and parentOf(i) is (i-1)/2




回答8:


The peek() method does not remove anything from the queue, but because of this, it will continually get the top value until it IS empty. I'm guessing you checked if it was empty after your while loop, which would give you this conclusion.

The only way to do this is to sort it yourself. You can get the original comparator for it like this:

Event[] events = Arrays.sort(pq.toArray(), pq.comparator());
for (Event e : events) {
    // do stuff
}



回答9:


for (Event event: pq.toArray(new Event[pq.size()])) {
    event.toString();
}


来源:https://stackoverflow.com/questions/8129122/how-to-iterate-over-a-priorityqueue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!