堆 - Heap

基本概念

堆是一种数据结构,定义为一棵完全二叉树。假如用数组储存堆结构,那么对于某个index为i的节点来说,它的左儿子的index为2*i+1,右儿子为2*i+2
堆有两种,小根堆和大根堆。对于小根堆,它的每个节点的值都小于该节点左右儿子的值。同理大根堆。

堆的操作

  • 堆化(heapify)
    O(n)
    表面上看heapify应该为O(nlogn),但是对于在第h-i层的节点来说,它最多的shiftdown深度为ishiftdown每一层的复杂度为O(1),而第h - i层一共有2 ^ {h - i}个节点, 所以整个heapify的时间复杂度为:
    2^{h - 1} *1 + 2^{h - 2} *2 +...+ 2^{1} *(h - 1) + h
    这是一个等比数列,通过将它乘以2,并做差,得到:
    2^{h+1} - 2 - h
    因为h = logn,所以heapify的时间复杂度为O(n)
public class Heap {
    
    public void heapify(int[] A) {
        for (int i = (A.length - 2) / 2; i >= 0; i--) {
            shiftdown(A, i);
        }
    }
    
    public void shiftdown(int[] A, int k) {
        int n = A.length;
        int minIndex = k;
        int left = 2 * k + 1;
        int right = 2 * k + 2;
        if (left < n && A[left] < A[minIndex]) {
            minIndex = left;
        }
        if (right < n && A[right] < A[minIndex]) {
            minIndex = right;
        }
        if (minIndex != k) {
            int tmp = A[k];
            A[k] = A[minIndex];
            A[minIndex] = tmp;
            shiftdown(A, minIndex);
        }
    }
}
  • 添加
    O(logn)
  • 删除
    O(logn)
  • 返回堆顶
    O(1)
public class minHeap {
    
    int[] A;
    int size;
    int maxSize;
    
    public minHeap(int n) {
        A = new int[n];
        size = 0;
        maxSize = n;
    }
    
    public void add(int x) {
        if (size == A.length) {
            return;
        }
        A[size] = x;
        shiftup(size);
        size++;
    }
    
    public int poll() {
        if (size == 0) {
            return Integer.MIN_VALUE;
        }
        size--;
        swap(0, size);
        shiftdown(0);
        return A[size];
    }
    
    public int peek() {
        if (size == 0) {
            return Integer.MIN_VALUE;
        }
        return A[0];
    }
    
    private void shiftdown(int k) {
        int minIndex = k;
        int left = 2 * k + 1;
        int right = 2 * k + 2;
        if (left < size && A[left] < A[minIndex]) {
            minIndex = left;
        }
        if (right < size && A[right] < A[minIndex]) {
            minIndex = right;
        }
        if (minIndex != k) {
            swap(minIndex, k);
            shiftdown(A, minIndex);
        }
    }
    
    private void shiftup(int k) {
        int parent = k / 2;
        if (A[k] < A[parent]) {
            swap[k, parent];
            shiftup(parent);
        }
    }
    
    private void swap(int a, int b) {
        int tmp = A[a];
        A[a] = A[b];
        A[b] = tmp;
    }
}
  • Java 内置PriorityQueue
PriorityQueue<Integer> heap = new PriorityQueue<>(size, new Comparator<Integer>() {
        @Override
        public int compare {
                return a - b; // 小根堆 
                return b - a; // 大根堆
        }
});
heap.offer(); // 添加
heap.poll(); // 删除
heap.peek(); // 返回堆顶元素,即最小或最大值

Lintcode 相关练习

Top k Largest Numbers II
K Closest Points

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 堆就是用数组实现的二叉树,所以它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。...
    唐先僧阅读 249,727评论 21 252
  • 什么是堆? 堆是满足下面两个条件的一种二叉树 它是一棵完全二叉树; 堆中每个节点的值都必须大于等于(大根堆)或者小...
    币来币往阅读 3,222评论 0 0
  • 一:堆的介绍 Heap是一种数据结构具有以下的特点:1)完全二叉树;2)heap中存储的值是偏序; Min-hea...
    梦工厂阅读 7,013评论 2 7
  • “堆”这种数据结构常用在“优先级队列”的实现上, 比如Java中的PriorityQueue。今天讲讲什么是堆,如...
    昵称全尼马被注册了阅读 4,580评论 0 1
  • 快月考的那段时间,天就想破了洞一样,雨一下就是好几天,体弱多病的自己自然是逃不过感冒的厄运,流涕,头疼,发烧,各种...
    七汐子阅读 2,425评论 0 1