堆的应用----堆排序,topk问题

一、堆排序

    //堆排序
    public static void heapSort(int[] arr) {
        // 1. 先进行建堆
        createHeap(arr);
        // 2. 循环进行交换堆顶元素和最后一个元素的过程, 并且删除该元素, 进行向下调整
        int heapSize = arr.length;
        for (int i = 0; i < arr.length; i++) {
            swap(arr, 0, heapSize - 1);
            // 删除最后一个元素
            heapSize--;
            // 从 0 这个位置进行向下调整
            shiftDown(arr, heapSize, 0);
        }
    }
    public static void shiftDown(int[] arr, int size, int index) {
        int parent = index;
        int child = 2 * parent + 1;
        while (child < size) {
            if (child + 1 < size && arr[child + 1] > arr[child]) {
                child = child + 1;
            }
            // 经过上面的 if 之后, child 就指向了左右子树中的较大值.
            // 比较 child 和 parent 的大小
            if (arr[parent] < arr[child]) {
                // 不符合大堆要求
                swap(arr, parent, child);
            } else {
                break;
            }
            parent = child;
            child = 2 * parent + 1;
        }
    }
    public static void createHeap(int[] arr) {
        for (int i = (arr.length - 1 - 1) / 2; i >= 0; i--) {
            shiftDown(arr, arr.length, i);
        }
    }
    public static void swap(int[] arr, int x, int y) {
        int tmp = arr[x];
        arr[x] = arr[y];
        arr[y] = tmp;
    }

二、topk问题(面试题) 

假设有一亿个数据,找出前 1000 个最大的数字
使用堆解决 topk 问题,有两种方案:
方案一、直接针对这一亿个数据的数组,进行建大堆
       接下来循环 1000 次,进行取堆顶元素/删除堆顶元素操作
       特点:得到的这前 1000 个数据是有序的
方案二、创建一个大小为 1000 的小堆,遍历这一亿个数据,依次往堆里插入
       如果堆没满,直接插入
       如果堆满了(小堆的堆顶元素就是这个堆里最小的元素),拿当前值和堆顶元素比较
       如果当前值小于堆顶元素,就 pass
       如果当前值大于堆顶元素,就删除堆顶元素,将当前值插入堆中
       特点:效率更高;得到的 1000 个数据不保证顺序

海量数据处理,内存存不下,怎么办?
假设有 100 万亿个数据,内存存不下,找前 1000 个最大数据?(方案二)
将 100 万亿个数据存到磁盘上,内存中只存大小为 1000 的小堆,
每次从磁盘上读取一个数据,和堆顶元素比较并更新即可
上一篇:go每日新闻(2021-07-28)——字节跳动高频算法TopK


下一篇:收藏基础算法刷题好的评论