Java中使用优先队列PriorityQueue实现堆

文章目录

  • 1. 堆的定义
  • 2. 堆的常见操作
  • 3. Java中的PriorityQueue
    • 3.1 PriorityQueue简介
    • 3.2 PriorityQueue常见方法
    • 3.3 例子
      • 问题
      • 代码

1. 堆的定义

堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。
  • 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

常见的堆有二叉堆、斐波那契堆等。
堆是线性数据结构,相当于一维数组,有唯一后继。
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(ki<= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4…n/2)
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。

2. 堆的常见操作

堆支持以下的基本:

  • build:建立一个空堆;
  • insert:向堆中插入一个新元素;
  • update:将新元素提升使其符合堆的性质;
  • get:获取当前堆顶元素的值;
  • delete:删除堆顶元素;
  • heapify:使删除堆顶元素的堆再次成为堆。
    某些堆实现还支持其他的一些操作,如斐波那契堆支持检查一个堆中是否存在某个元素

3. Java中的PriorityQueue

3.1 PriorityQueue简介

参考:https://www.cnblogs.com/CarpenterLee/p/5488070.html
Java中PriorityQueue通过二叉小顶堆实现,可以用一棵完全二叉树表示。优先队列的作用是能保证每次取出的元素都是队列中权值最小的。这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序(natural ordering),也可以通过构造时传入的比较器(Comparator,类似于C++的仿函数)。

Java中PriorityQueue实现了Queue接口,不允许放入null元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值),也就意味着可以通过数组来作为PriorityQueue的底层实现。其中,父节点和子节点的编号是有联系的,更确切的说父子节点的编号之间有如下关系:
leftNo = parentNo2+1
rightNo = parentNo
2+2
parentNo = (nodeNo-1)/2
通过上述三个公式,可以轻易计算出某个节点的父节点以及子节点的下标。这也就是为什么可以直接用数组来存储堆的原因。

3.2 PriorityQueue常见方法

PriorityQueue的peek()和element操作是常数时间,add(), offer(), 无参数的remove()以及poll()方法的时间复杂度都是log(N)。

  • boolean add(E e)
    Inserts the specified element into this priority queue.
  • boolean offer(E e)
    Inserts the specified element into this priority queue.
    前者在插入失败时抛出异常,后则则会返回false

  • E peek()
    Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty.

  • E poll()
    Retrieves and removes the head of this queue, or returns null if this queue is empty.
  • boolean remove(Object o)
    Removes a single instance of the specified element from this queue, if it is present.

3.3 例子

问题

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

Example 1:

Input: [3,2,1,5,6,4] and k = 2
Output: 5
Example 2:

Input: [3,2,3,1,2,4,5,5,6] and k = 4
Output: 4

代码

public class Solution {
            public int findKthLargest(int[] nums, int k) {
                PriorityQueue<Integer> largeK = new PriorityQueue<Integer>(k + 1);
    
                for(int el : nums) {
                    largeK.add(el);
                    if (largeK.size() > k) {
                        largeK.poll();
                    }
                }

                return largeK.poll();
            }
}

你可能感兴趣的:(Java,数据结构和算法)