PriorityQueue可以自定义传入的Comparator来比较内部元素的大小,Comparator比较时的返回如下:
如果o1 == o2 ,返回0
如果o1 < o2 ,即 o1-o2 < 0 ,则返回负数
如果o1 > o2 ,即 o1-o2 > 0 ,则返回正数
如下是PriorityQueue类中新放入元素时执行的代码,x是新放入的元素,k是队列大小,这里只要关注x就好了。可以看到满足 comparator.compare(x, (E) e) >= 0 时会跳出循环,e是队列中原先就存在的元素,即输入的x停止继续往堆顶上升:
private void siftUpUsingComparator(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
所以当使用如下自定义比较器时,o1对应x(输入的元素),o2对应e(队列中原有的元素):
new PriorityQueue<>(k, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } })
此时如果o1-o2>=0,即x>=e时,x会停止往堆顶上升。否则如果o1-o2<0,即x<e时(即输入的元素值x会比较小),x会继续往堆顶上升,这样构建出来的就是最小堆,堆顶的元素值最小。
代码换一下,变成o2-o1。此时如果o2-o1>=0,即e>=x时,x会停止往堆顶上升。否则如果o2-o1>=0,即e<x时(即输入的元素值x会比较大),x会继续往堆顶上升,这样构建出来的就是最大堆,堆顶的元素值最大:
new PriorityQueue<>(k, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o2 - o1; } })
总结下就是,比较器比较o1 和 o2时,如果o1比较大,o1比较大会停止继续往堆顶上升,此时就是最小堆;如果o1比较小,那就是最大堆。