Sorting Priority Queue in Java [duplicate]

余生颓废 提交于 2019-12-20 11:59:04

问题


I was trying to insert the integers in PriorityQueue, and I know that :

If no comparator is specified when a PriorityQueue is constructed, then the default comparator for the type of data stored in the queue is used. The default comparator will order the queue in ascending order

However, the output I am getting is not in sorted order. Output after running the below code is : [2, 4, 8, 6]

public static void main(String args[]) {
    PriorityQueue<Integer> q = new PriorityQueue<Integer>(10);
    q.offer(4);
    q.offer(2);
    q.offer(8);
    q.offer(6);

    System.out.print(q);
}

Can someone please explain why ?


回答1:


A PriorityQueue is what is called a binary heap. It is only ordered/sorted in the sense that the first element is the least. In other word, it only cares about what is in the front of the queue, the rest are "ordered" when needed.

The elements are only ordered as they are dequeued, i.e. removed from the queue using poll(). This is the reason why a PriorityQueue manages to have such good performance, as it is not doing any more sorting than it needs at any time.

If you want to know how heaps work in detail I recommend this MIT lecture on heaps.




回答2:


When you call System.out.print() on your PriorityQueue, it will not poll() your elements from it, but call toString(). PriorityQueue doesn't implement toString(), so it's the toString() from AbstractCollection which will be called:

public String toString() {
    Iterator<E> i = iterator();
if (! i.hasNext())
    return "[]";

StringBuilder sb = new StringBuilder();
sb.append('[');
for (;;) {
    E e = i.next();
    sb.append(e == this ? "(this Collection)" : e);
    if (! i.hasNext())
    return sb.append(']').toString();
    sb.append(", ");
}
}

As you can see, this method only iterate the PriorityQueue. As you can see in the PriorityQueue javadoc:

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

If you want to use the PriorityQueue as it is intented to be used, you have to poll() each value and print it:

while (!q.isEmpty()) {
    Integer i = q.poll();
    System.out.println(i);
}

Output:

2
4
6
8



回答3:


That's because java.util.PriorityQueue implements a binary heap.

Unfortunately, there is no easy way to sort a PriorityQueue. If you poll() objects until the queue is empty, the elements will be in the comparator's order. That's why when I was faced with a similar problem I've implemented my own heap class that allows me to sort the elements after the fact; which I use for a top N list of a large number of elements.

(Since I made the class on the job, I don't have the right to post it here, but it's largely modeled after python's heap.py, so there's a good source of inspiration)




回答4:


An unbounded priority queue is based on a priority heap

Priority Queue.Offer() method uses siftUpComparable() internally to insert items when passed without comparator

siftUpComparable compares current element with all elements at Parent Positions(int i = paramInt - 1 >>> 1;) until the Heap condition is met


siftUpComparable Algorithm in Nutshell (if implemented through array Root=index 0):

1.Add the element to the bottom level of the heap.
2.Compare the added element with its parent; if they are in the correct order, stop.
3.If not, swap the element with its parent and return to the previous step.

Java Code

  private void siftUpComparable(int paramInt, E paramE)
  {
    Comparable localComparable = (Comparable)paramE;
    while (paramInt > 0)
    {
      int i = paramInt - 1 >>> 1;
      Object localObject = this.queue[i];
      if (localComparable.compareTo(localObject) >= 0) {
        break;
      }
      this.queue[paramInt] = localObject;
      paramInt = i;
    }
    this.queue[paramInt] = localComparable;
  }

In Your example:

q.offer(4); -> Inserts 4

Result: PQ[0]=4


q.offer(2); -> siftUpComparable compares 4 to 2 and swap positions (comparisons at Parent Locations)

Result: PQ[0]=2,PQ[1]=4


q.offer(8); -> siftUpComparable Compares 8 and 2 (since 2 is at Parent Location)

Result: PQ[2]=8


q.offer(6);: -> siftUp Compares 6 with 4 (Parent of location 3 is Location 1 according to paramInt - 1 >>> 1; logic )

Result: PQ[3]=6


Final PQ=[2, 4, 8, 6]




回答5:


How java priority Queue is suppose to work?

Basically your print statement does not traverse the tree in order.



来源:https://stackoverflow.com/questions/25569625/sorting-priority-queue-in-java

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