优先级队列(堆) PriorityQueue

发布时间:2024年01月21日

  • 🎥?个人主页:Dikz12
  • 📕格言:那些在暗处执拗生长的花,终有一日会馥郁传香
  • 欢迎大家👍点赞?评论?收藏

目录

?1.优先级队列?

2.优先级队列的模拟实现

2.1 堆的概念

2.2 堆的创建?

2.3 堆的插入和删除?

2.4 建堆的时间复杂度

?3.PriorityQueue接口介绍


?1.优先级队列?

? ?有些情况下,操作的数据可能带有优先级,一般出队列时,可能需要优先级高的元素先出队列,该中场景下,使用队列显然不合适,比如:初中那会班主任排座位时可能会让成绩好的同学先挑座位。

2.优先级队列的模拟实现

优先级队列 (?Priority Queue)底层使用了这种数据结构,而堆实际上就是对完全二叉树进行了一些调整。

2.1 堆的概念

?堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父(根)节点的值;
  • ?堆是一颗完全二叉树

?所以,堆可以分为大根堆和小根堆,也都是完全二叉树。

  • ?小根堆:根节点 比 左右孩子都小;左右孩子谁最小没有关系,只考虑根和左右孩子的关系

  • 大根堆:?根节点 比 左右孩子都大

2.2 堆的创建?

?对于集合{ 27,15,19,18,28,34,65,49,25,37 }中的数据,如果将其创建成堆呢?

?可以采用向下调整方式,创建大/小根堆:

创建大根堆 :

?整个调整过程:

1.从最后一颗子树开始调整

2.找到左右孩子的最大值 和 根节点进行比较,如果比根节点大,那么就交换

3.如果能够知道子树的根节点下标,那么下一颗子树的位置就是当前根节点下标 -1

4.一直调整到下标为0结束

关键问题:

1.每棵子树调整的时候,什么时候结束?

? 就是孩子的下标要小于length

2.最后一颗子树的根节点下标如何确定?

(9-1) / 2 => (length -1) / 2

    public void createBigHeap() {
        for (int parent = (usedSize - 1 - 1) / 2; parent >= 0; parent--) {
            siftDown(parent,usedSize);
        }
    }
    public void siftDown(int parent, int end) {

        int child = parent * 2 + 1;
        while (child < end) {
            if (child + 1 < usedSize && elem[child] < elem[child + 1]) {
                child++;
            }
            //开始调整 此时child下标,一定是最大值
            if (elem[child] > elem[parent]) {
                //交换
                swap(child, parent);
                //交换之后,验证下面是否还满足大根堆
                parent = child;
                child = parent * 2 + 1;
            } else {
                //都满足
                break;
            }
        }
    }
    public void swap(int i,int j) {
        int tmp = elem[i];
        elem[i] = elem[j];
        elem[j] = tmp;
    }

2.3 堆的插入和删除?

?插入:

?

1.判断是否需要扩容

2.把插入的值放到最后

3.开始向上调整

关键问题:

?什么时候调整结束?

4? 到---> 1? : (p?- 1)/ 2 ,在 c = p,?由此推-> 当 c == 0 或者 p < 0 结束?。

插入后:


    //插入
    public void offer(int val) {
        //1.是否需要扩容
        if (isFull()) {
            this.elem = Arrays.copyOf(elem,2*elem.length);
        }
        //2.向上调整
        elem[usedSize] = val;
        siftUp(usedSize);
        usedSize++;
    }
    public void siftUp(int child) {
        int parent = (child - 1) / 2;
        while (child > 0) {
            if (elem[child] > elem[parent]) {
                swap(child,parent);
                child = parent;
                parent = (child - 1) / 2;
            } else {
                break;
            }
        }
    }
    public boolean isFull() {
        return usedSize == elem.length;
    }

删除:

1.交换0 和 最后一个下标的值,uesdSize--

2.在向下调整就行

    //删除
    public int poll() {
        if (empty()) {
            return -1;
        }
        int delVal = elem[0];
        swap(0,usedSize-1);
        usedSize--;
        siftDown(0,usedSize);
        return delVal;
    }
    public boolean empty() {
        return usedSize == 0;
    }

2.4 建堆的时间复杂度

因此,堆向下调整建堆的时间复杂度为O(n)。

?3.PriorityQueue接口介绍

?注意:

1. 使用时必须导入PriorityQueue所在的包,即:

import java.util.PriorityQueue;

2. PriorityQueue中放置的元素必须要能够比较大小,不能插入无法比较大小的对象,否则会抛出
ClassCastException异常。
3. 不能插入null对象,否则会抛出NullPointerException。
4. 没有容量限制,可以插入任意多个元素,其内部可以自动扩容。
5. 插入和删除元素的时间复杂度为O(log2N)。
6. PriorityQueue底层使用了堆数据结构。
7. PriorityQueue默认情况下是小堆---即每次获取到的元素都是最小的元素。
?

文章来源:https://blog.csdn.net/m0_65465009/article/details/135726789
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。