• 经典算法(一) top k


    问题:1亿数据中,找出最大的k个数,要求使用内存不超过1m

    (延伸问题:1亿数据中,找出重复出现次数最多的k个,要求使用内存不超过1m 等)

    分析:

    1亿数字(int)占内存:100000000 * 4byte / 1024 / 1024 =381m

    其中 int=4byte,1m=1024kb,1kb=1024b

    实现:

    维护一个k大小的数组有序数组。每次加进来新的,都要判断是不是 换掉 该数组中最小的元素,如果需要,则删除最小元素,放入新元素,并重新排序。

    基于小顶堆的实现:

    创建一个k大小的堆。TOP K堆只用维护固定数量的元素,每次加进来新的,都要判断是否替换掉堆顶元素,如果需要,则删除堆顶元素,放入新元素,并重新构造堆

    时间复杂度O(nlnK)

    public class TopK_ByHeapSort {
        
        //向小顶堆插入一个新的元素
        public static void insertHeap(int[] heap, int value) {
            heap[0] = value;
            adjustHeap(heap, 0, heap.length);// 重新对堆进行调整
        }
    
        //调整堆
        public static void adjustHeap(int[] arr, int i, int length) {
            int temp = arr[i];// 先取出当前元素i
            for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {// 从i结点的左子结点开始,也就是2i+1处开始
                if (k + 1 < length && arr[k] > arr[k + 1]) {// 如果左子结点小于右子结点,k指向右子结点
                    k++;
                }
                if (arr[k] < temp) {// 如果子节点小于父节点,将子节点值赋给父节点(不用进行交换)
                    arr[i] = arr[k];
                    i = k;
                } else {
                    break;
                }
            }
            arr[i] = temp;// 将temp值放到最终的位置
        }
    
        
        //构建小顶堆
        public static void createMinHeap(int[] arr){
            for (int i = arr.length / 2 - 1; i >= 0; i--) {
                adjustHeap(arr, i, arr.length);
            }
        }
        //交换元素
        public static void swap(int[] arr, int a, int b) {
            int temp = arr[a];
            arr[a] = arr[b];
            arr[b] = temp;
        }
        
        //将小顶堆 转化为 有序数组
        public static int[] minHeapToSortArr(int[] arr){
            for (int j = arr.length - 1; j > 0; j--) {
                swap(arr, 0, j);// 将堆顶元素与末尾元素进行交换
                adjustHeap(arr, 0, j);// 重新对堆进行调整
            }
            return arr;
            
        }
        
        public static void print(int[] n) {
            for (int i = 0; i < n.length; i++) {
                System.out.print(" " + n[i]);
            }
            System.out.println();
        }
        //使用堆排序实现topk
        public static int[] getTopKByHeap(int input[], int k) {
            //构建k大小数组
            int[] result = new int[k];
            for (int i = 0; i < k; i++)
                result[i] = input[i];
            //构建小顶堆
            createMinHeap(result);
            
            //将新元素插入小顶堆
            for (int i = k; i < input.length; i++) {
                if (input[i] > result[0])
                    insertHeap(result, input[i]); // 复杂度最坏是O(nlgK),而且内存消耗就K,不然海量数据排序,内存放不下,得用归并排序,最好最坏平均都是
            }
            //将小顶堆转化为有序数组
            minHeapToSortArr(result);
            return result;
        }
    
        public static void main(String[] args) {
            int input[] = { 37, 3, 5, 29, 2, 9, 10, 40, 99 };
            int k=6;
            print(getTopKByHeap(input, k));
        }
    }

     延伸问题:1亿数据中,找出重复出现次数最多的k个,要求使用内存不超过1m 

    1亿数据占内存381m,可分成400批load到内存
    1亿/400=25w
    通过hash,大顶堆 分别计算每25w数据中重复次数最多的k个元素,然后合并这400个大顶堆

  • 相关阅读:
    IO模型
    协程
    线程
    进程
    网络编程
    模块二
    面向对象(二)
    面向对象(一)
    优化异常报错
    python 模块
  • 原文地址:https://www.cnblogs.com/amei0/p/8318322.html
Copyright © 2020-2023  润新知