PriorityQueue优先级队列

简介: PriorityQueue优先级队列

前言

优先级队列就是在堆的基础上进行改造,那么什么是堆,又什么是优先级队列呢?

我们一起来看看吧!




目录

前言

一、堆

(一)堆的创建

(二)堆的插入

(三)堆的删除

(四)模拟实现堆

二、优先级队列

(一)常用方法:

(二)常考点

结语


一、堆

堆就是堆中某个节点的值总是不大于或不小于其父节点的值。

堆总是完全二叉树。

Java底层的堆是顺序表,按照层序遍历的规则存储数据。
堆分为小根堆和大根堆。

1.小根堆(又名最小堆)

就是堆中某个节点的值总是不小于其父节点的值。

例如:


2.大根堆(又名最大堆)

就是堆中某个节点的值总是不大于其父节点的值。

例如:

以创建最小堆为例,给出的数据顺序是: 5、3、6、7、4、2.

(一)堆的创建

首先,根据给出的数据顺序,创建如下二叉树:

从最后一个叶子节点开始调整(向上调整):


时间复杂度是:O(n)

(二)堆的插入

假设要插入数据0:

如果在插入数据时,堆满扩容;调整为向上调整

时间复杂度是:O(log n)

(三)堆的删除

堆的删除一定删除的是堆顶元素。

时间复杂度是:O(log n)

(四)模拟实现堆

代码:

import java.util.Arrays;
import java.util.Comparator;
class PriorityException extends RuntimeException{
    public PriorityException(String s){
        super(s);
    }
}
public class MyPriortyQueue implements Comparator<Integer> {
    public int[] elem;
    public int usedSize;
    public MyPriortyQueue(int k) {
        elem = new int[k];
    }
    public MyPriortyQueue() {
        elem = new int[11];
    }
    @Override
    public int compare(Integer o1,Integer o2) {
        return o2.compareTo(o1);
    }
    /**
     * 建堆
     */
    public void createHeap(int[] array) {
        for(int i = 0; i < array.length; i++){
            elem[i] = array[i];
            usedSize++;
        }
        for(int i = (usedSize-1-1)/2; i >= 0; i--){
            shiftDown(i,usedSize-1);
        }
    }
    /**
     * 向下调整
     * @param root 是每棵子树的根节点的下标
     * @param len  是每棵子树调整结束的结束条件
     * 向下调整的时间复杂度:O(logn)
     */
    private void shiftDown(int root,int len) {
        int child = root*2+1;
        while(child < len){
            if(child+1<len && compare(elem[child],elem[child+1])>0){
                child++;
            }
            if(compare(elem[root],elem[child])>0){
                int tmp = elem[root];
                elem[root] = elem[child];
                elem[child] = tmp;
                root = child;
                child = root*2+1;
            }else{
                break;
            }
        }
    }
    /**
     * 入队:仍然要保持是大根堆
     * @param val
     */
    public void push(int val) {
        if(isEmpty()){
            elem[0] = val;
        }else{
            elem[usedSize] = val;
        }
        usedSize++;
        shiftUp(usedSize-1);
    }
    /**
     * 向上调整
     * 默认除了需要调整的地方外,其余都是已经调整好了的
     */
    private void shiftUp(int child) {
        int parent = (child-1)/2;
        while(child > 0){
            if(compare(elem[parent],elem[child])>0){
                int tmp = elem[parent];
                elem[parent] = elem[child];
                elem[child] = tmp;
                child = parent;
                parent = (child-1)/2;
            }else{
                break;
            }
        }
    }
    public boolean isFull() {
        return usedSize == elem.length;
    }
    /**
     * 出队【删除】:每次删除的都是优先级高的元素
     * 仍然要保持是大根堆
     */
    public void pollHeap() throws PriorityException{
        if(isEmpty()){
            throw new PriorityException("pollHeap::队列无元素,删除失败");
        }
        elem[0] = elem[usedSize-1];
        usedSize--;
        shiftDown(0, usedSize-1);
    }
    public boolean isEmpty() {
        return usedSize == 0;
    }
    /**
     * 获取堆顶元素
     * @return
     */
    public int peekHeap() throws PriorityException{
        if(isEmpty()){
            throw new PriorityException("peekEmpty::队列无元素,获取失败");
        }
        return elem[0];
    }
    public static void main(String[] args) {
        MyPriortyQueue p = new MyPriortyQueue();
        int[] arr = {2,4,2,5,7,9,5,3};
        p.createHeap(arr);
        System.out.println("+=========创建一个堆========+");
        System.out.println(Arrays.toString(p.elem));
        p.push(10);
        System.out.println("+=========入一个值========+");
        System.out.println(Arrays.toString(p.elem));
        System.out.println("+=========输出堆顶========+");
        System.out.println(p.peekHeap());
        p.pollHeap();
        System.out.println("+=========删除堆顶=======+");
        System.out.println(Arrays.toString(p.elem));
    }
}

代码链接在GitHub:堆_练习模拟实现2 · Yjun6/DataStructrue@98faae5 (github.com)

二、优先级队列

PriorityQueue<Integer> p = new PriorityQueue<>();

(一)常用方法:

boolean offer(E e) 插入元素e,成功插入返回true;会自动扩容;如果e为空,会抛出异常
E peek() 获取优先级队列最高的元素;若队列为空,返回null
E poll() 移除优先级队列最高的元素;若队列为空,返回null
int size() 获取有效元素个数
void clear() 清空
boolean isEmpty() 判断是否为空

关于创建优先级队列的方法:

PriorityQueue() 初始容量为11,默认无比较器
PriorityQueue(int k) 初始容量为k,k>0
PriorityQueue(Collection<? extend E> c) 用一个集合创建优先级队列

优先级队列扩容说明:

  • 如果容量小于64,按照2倍扩容;
  • 如果容量大于等于64,按照1.5倍扩容;
  • 如果容量超过 MAX_ARRAY_SIZE,按照 MAX_ARRAY_SIZE 进行扩容。

(二)常考点

求前k个最大值、前k个最小值、第k个最大值、第k个最小值……

面试题 17.14. 最小K个数 - 力扣(Leetcode)

代码:

class Solution {
    public int[] smallestK(int[] arr, int k) {
        if(arr == null || k == 0) return new int[k];
        Comp comp = new Comp();
        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(comp);//求大根堆
        for(int i = 0; i < k; i++){
            priorityQueue.offer(arr[i]);
        }
        for(int i = k; i < arr.length; i++){
            if(arr[i] < priorityQueue.peek()){
                priorityQueue.poll();
                priorityQueue.offer(arr[i]);
            }
        }
        int[] str = new int[priorityQueue.size()];
        for(int i = 0; i < str.length; i++){
            str[i] = priorityQueue.poll();
        }
        return str;
    }
}
class Comp implements Comparator<Integer> {
    @Override
    public int compare(Integer a, Integer b){
        return b.compareTo(a);
    }
}

结语

小编能力有限,欢迎大家指出错误哦~

这篇博客如果对你有帮助,给博主一个免费的点赞以示鼓励,欢迎各位🔎点赞👍评论收藏⭐,谢谢!!!

相关文章
|
6月前
堆(优先级队列 PriorityQueue)
堆(优先级队列 PriorityQueue)
41 0
|
Java 调度
【PriorityQueue优先级队列及其应用】
【PriorityQueue优先级队列及其应用】
|
存储 安全 索引
认真研究队列中的优先级队列PriorityQueue
认真研究队列中的优先级队列PriorityQueue
75 0
|
3月前
|
存储 设计模式 算法
【C++】deque以及优先级队列
【C++】deque以及优先级队列
|
5月前
|
C++ 容器
【C++】学习笔记——优先级队列
【C++】学习笔记——优先级队列
41 0
|
6月前
|
存储 安全 Java
优先级队列
优先级队列
|
人工智能 算法 搜索推荐
我学会了,封装自己的优先队列PriorityQueue
优先队列本身就是一种队列。 普通队列:先进先出、后进后出,如排队买票吃饭一样。 优先队列:出队顺序和入队顺序无关,和优先级相关。如去医院看病,床位非常的紧张,需要排队才能去做手术的话,此时做手术的这个队伍的顺序就是一个优先队列。因为医生是根据每一个患者的病症的不同以及需要这个手术的紧急程度的不同来去安排谁先做手术谁后做手术,也可以认为每一个患者是有一个优先级的。优先级高者先得,这样的一个队列就叫做优先队列,它和普通队列最主要的区别是在于出队这个操作上,入队很简单,但是优先级高的先出队。
231 0
我学会了,封装自己的优先队列PriorityQueue
|
存储
优先级队列详解
优先级队列详解
113 0
|
存储 机器学习/深度学习 算法
PriorityQueue
PriorityQueue
115 0
PriorityQueue
|
安全 Java
Java集合框架(PriorityQueue优先级队列讲解)
Java集合框架(PriorityQueue优先级队列讲解)
139 0