前K个数(java)

题目描述

  • 求求海量数据(正整数)按逆序排列的前k个数(topK),因为数据量太大,不能全部存储在内存中,只能一个一个地从磁盘或者网络上读取数据,请设计一个高效的算法来解决这个问题。 第一行用户输入K,代表要求得topK 随后的N(不限制)行,每一行是一个整数代表用户输入的数据 直到用户输入-1代表输入终止 请输出topK,空格分割。

解题思路

  • 最终需要逆序排列的前K个数,则一直维持一个大小为K的数组,当用户输入到数组被填满后(达到k个),对数组进行堆化(小顶堆),从此对每一个输入的数据与对顶元素进行比较,若比堆顶元素大(属于TopK)则替换掉堆顶元素,并进行小顶堆调整,直到输入结束,输出TopK。

代码

static int index=0;
    static int[] heap;
    static int k;

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        k=sc.nextInt();
        heap=new int[k];
        int x=sc.nextInt();
        while(x!=-1){
            deal(x);
            x=sc.nextInt();
        }
        System.out.println(Arrays.toString(heap));
    }

    private static void deal(int x) {
        if(index<k){
            heap[index++]=x;
            //当topK存满则进行堆化(小顶堆)
            if(index==k){
                buildMinHeap(heap,heap.length);
            }
        }else {
            if(heap[0]<x){
                heap[0]=x;
                minHeadAdjust(heap,0,heap.length);
                System.out.println(Arrays.toString(heap));
            }
        }

    }

    private static void buildMinHeap(int[] heap, int length) {
        //减一因为0号位也存有元素
        for (int i = length/2-1; i >0 ; i--) {
            minHeadAdjust(heap,i,heap.length);
        }
    }

    private static void minHeadAdjust(int[] heap, int i, int length) {
        //找到左右孩子
        int left=i*2+1;
        int right=i*2+2;

        //该节点为叶子节点
        if(left>=length){
            return;
        }
		//寻找孩子节点中最小的一个
        int min=left;
        if(right<length&&heap[right]<heap[left]){
            min=right;
        }

        if(heap[i]<=heap[min]){
            return;
        }else {
            int temp=heap[i];
            heap[i]=heap[min];
            heap[min]=temp;
        }
        minHeadAdjust(heap,min,heap.length);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值