二叉堆 与 PriorityQueue

堆在存储器中的表示是数组,堆只是一个概念上的表示。堆的同一节点的左右子节点都没有规律。
堆适合优先级队列(默认排列顺序是升序排列,快速插入与删除最大/最小值)。

数组与堆

堆(完全二叉树)

堆实现的优先级队列虽然和数组实现相比删除慢了些,但插入的时间快的多了:
    当速度很重要且有很多插入操作时,可以选择堆来实现优先级队列。
    堆插入删除的效率:时间复杂度是:O(logn)。


小顶堆:父节点的值 <= 左右孩子节点的值
大顶堆:父节点的值 >= 左右孩子节点的值


堆的定义:n个关键字序列array[0,...,n-1]:

    若array[0,...,n-1]表示一颗完全二叉树的顺序存储模式,则双亲节点指针和孩子结点指针之间的内在关系如下:

        任意一节点指针 i(0 <= i <= (n-1)/2) : 父节点:i==0 ? null : (i-1)/2

                左孩子:2*i + 1

                右孩子:2*i + 2

    ① array[i] <= array[2*i + 1] 且 array[i] <= array[2*i + 2] : 称为小根堆

    ② array[i] >= array[2*i + 1] 且 array[i] >= array[2*i + 2] : 称为大根堆


堆的插入(add(e),offer(e):添加到末尾,由于可能破坏堆结构,需要调整):

    插入使用向上筛选,向上筛选的算法比向下筛选的算法相对简单,因为它不需要比较两个子节点关键字值的大小


删除操作 ( remove(o) ):

    由于可能破坏堆结构,需要调整


删除堆顶 ( poll() ):

    移除是指删掉关键字值最大的节点,即根节点。移除思路如下:

  在被筛选节点的每个暂时停留的位置,向下筛选的算法总是要检查哪一个子节点更大,然后目标节点和较大的子节点交换位置

二叉堆的初始化

插入操作

删除操作

删除堆顶

堆排序

堆排序是一种树形选择排序方法,它的特点是:
    在排序的过程中,将array[0,...,n-1]看成是一颗完全二叉树的顺序存储结构,
    利用完全二叉树中双亲节点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(最小)的元素。


堆(二叉堆)排序的时间复杂度,最好,最差,平均都是O(nlogn),空间复杂度O(1),是不稳定的排序。

PriorityQueue

public class PriorityQueue<E> extends AbstractQueue<E>
    implements java.io.Serializable {

    private static final long serialVersionUID = -7720805057305804111L;

    private static final int DEFAULT_INITIAL_CAPACITY = 11;

    transient Object[] queue; // non-private to simplify nested class access

    int size;

    private final Comparator<? super E> comparator;

    transient int modCount;     // non-private to simplify nested class access

    public PriorityQueue(Collection<? extends E> c) {}  //使用已有集合构建二叉堆

    public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

    public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {

        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }
}


//自定义比较器,降序排列
static Comparator<Integer> cmp = new Comparator<Integer>() {
    public int compare(Integer e1, Integer e2) {
        return e2 - e1;
    }
};

在未排序的数组中找到第 k 个最大的元素

/**
 * 示例 1:
 *     输入: [3,2,1,5,5,4] 和 k = 2
 *     输出: 5
 *
 * 时间复杂度 : O(Nlogk)。
 * 空间复杂度 : O(k),用于存储堆元素。
 */

/**
 * 小顶堆
 */
class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        for (int i = 0; i < nums.length; i++) {
            pq.add(nums[i]);
            if(pq.size()>k)pq.poll();
        }
        return pq.poll();
    }
}

猜你喜欢

转载自www.cnblogs.com/loveer/p/11763116.html