本章主要内容

  • 堆排序
  • 堆和优先队列

什么是优先队列

  • 普通队列:先进先出;后进后出
  • 优先队列:出队顺序和入队顺序无关;和优先级有关

Java中优先队列的实现类是PriorityQueue

默认是最小堆,每次弹出最小值;最大堆需要自己传入Comparator,num2-num1 > 0

  • 新元素比堆顶元素大,就删除堆顶元素加入新元素,那么就是最大堆
  • 如果新数比堆顶元素小,则删除堆顶元素加入新元素,那就是最小堆

核心是如下两个函数

  • offer(元素):优先队列加入元素
  • poll():优先队列弹出最值元素

PriorityQueue的常见使用

// Java自带的优先队列PriorityQueue
int[] arr = new int[]{2, 5, 3, 9, 6, 4, 7};
System.out.println("原始数组内容:");
for (int i : arr) {
    System.out.print(i+" ");
}
System.out.println();

// 1.排序(升序, 默认)
System.out.println("PriorityQueue默认的升序(默认是最小堆,每次弹出最小值):");
PriorityQueue<Integer> pqAsc = new PriorityQueue<>();
for (int i : arr) {
    pqAsc.offer(i);
}
while (!pqAsc.isEmpty()) {
    System.out.print(pqAsc.poll() + " ");
}
System.out.println();

// 2.排序(降序)
System.out.println("PriorityQueue自定义的降序(自定义成最大堆,每次弹出最大值):");
PriorityQueue<Integer> pqDesc = new PriorityQueue<>(arr.length, new Comparator<Integer>() {
    @Override
    public int compare(Integer num1, Integer num2) {
        return num2.compareTo(num1);
    }
});
for (int i : arr) {
    pqDesc.offer(i);
}
while (!pqDesc.isEmpty()) {
    System.out.print(pqDesc.poll() + " ");
}
System.out.println();

// 3.取出最大的3个元素
System.out.println("取出最大的3个元素(默认是最小堆,每次弹出最小值):");
PriorityQueue<Integer> pqMax = new PriorityQueue<>();

for (int i : arr) {
    if (pqMax.size() < 3) {
        pqMax.offer(i);
    } else if (pqMax.peek() < i) {
        // 新元素大于堆顶元素,弹出堆顶元素,并把新的最大值加进去
        pqMax.poll();
        pqMax.offer(i);
    }
}
while (!pqMax.isEmpty()) {
    System.out.print(pqMax.poll() + " ");
}
System.out.println();

// 4.取出最小的3个元素
System.out.println("取出最小的3个元素(自定义成最大堆,每次弹出最大值):");
PriorityQueue<Integer> pqMin = new PriorityQueue<>(arr.length, new Comparator<Integer>() {
    @Override
    public int compare(Integer num1, Integer num2) {
        return num2.compareTo(num1);
    }
});

for (int i : arr) {
    if (pqMin.size() < 3) {
        pqMin.offer(i);
    } else if (pqMin.peek() > i) {
        // 新元素大于堆顶元素,弹出堆顶元素,并把新的最大值加进去
        pqMin.poll();
        pqMin.offer(i);
    }
}
while (!pqMin.isEmpty()) {
    System.out.print(pqMin.poll() + " ");
}
System.out.println();

结果如下:

原始数组内容:
2 5 3 9 6 4 7 
PriorityQueue默认的升序(默认是最小堆,每次弹出最小值):
2 3 4 5 6 7 9 
PriorityQueue自定义的降序(自定义成最大堆,每次弹出最大值):
9 7 6 5 4 3 2 
取出最大的3个元素(默认是最小堆,每次弹出最小值):
6 7 9 
取出最小的3个元素(自定义成最大堆,每次弹出最大值):
4 3 2

为什么使用优先队列?(优先队列的应用场景)

  • windows任务管理器中选择优先级最高的任务执行
  • 请求处理,优先处理重要人的请求
  • 从1000000个元素中选出前100名,抽象模型就是从N个元素中选出前M个元素