Search code examples
javadata-structurespriority-queue

Difference between Collections.reverseOrder vs custom comparator


I expect the two code snippets to produce the same result, yet they don't. Why? The only difference is the Comparator passed to the PriorityQueue constructor.

import java.util.Collections;
import java.util.PriorityQueue;

public class PriorityQueueTest {

  public static void main(String[] args) {
    PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
    int[] arr = {2,3,9,8,4};
    for (int i=0; i<arr.length; i++) {
      pq.add(arr[i]);
    }
    while(pq.size()>0) {
      System.out.println(pq.poll());
    }
  }
}

Output (correct / expected):

9
8
4
3
2
import java.util.Collections;
import java.util.PriorityQueue;

public class PriorityQueueTest {

  public static void main(String[] args) {
    PriorityQueue<Integer> pq = new PriorityQueue<>((a,b) -> a>b ? 0 : 1);
    int[] arr = {2,3,9,8,4};
    for (int i=0; i<arr.length; i++) {
      pq.add(arr[i]);
    }
    while(pq.size()>0) {
      System.out.println(pq.poll());
    }
  }
}

Output (wrong / unexpected):

2
9
8
4
3

Solution

  • Comparators must return 3 states: negative, 0 or positive, and must be self consistent such that compare(a,b) has same sign as -compare(b,a) when a!=b, and zero if a.equals(b).

    Your comparator does not satisfy these conditions. You are fortunate your answer works, but if you omit the 0 case in other comparators you may have issues in future.

    Instead use:

    PriorityQueue<Integer> pq = new PriorityQueue<>((a,b) -> a==b ? 0 : a>b ? -1 : 1);
    

    The above returns the order of elements you expect as for Collections.reverseOrder().