• 堆排序应用之topK问题


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

    思路:先开辟一个K大小的数组arr,然后读取K个数据存储到数组arr,读到K+1的时候,如果arr[K+1]小于arr中最小的值,那么就丢掉不管,如果arr[K+1]大于arr中最小的值,那么就把arr[K+1]和数组中最小的值进行交换,然后再读取K+2个数。这样就能解决这个问题。但是这个算法复杂度为K+(N-K)*K,K可以忽略不计,所以时间复杂度为O(KN)。那这个代码很容易就写出来。假如题目要求用到NlgK的时间复杂度,那么这里就需要使用堆这种数据结构来解决问题,而且还是小顶堆。具体思想还是和数组一样。

    代码:

     1 import java.util.Arrays;
     2 import java.util.Scanner;
     3 
     4 public class TopK {
     5 
     6     static int[] heap;
     7     static int index = 0;
     8     static int k;
     9     
    10     public static void main(String[] args) {
    11         Scanner scanner = new Scanner(System.in);
    12         k = scanner.nextInt();
    13         heap = new int[k];
    14         int x = scanner.nextInt();
    15         while(x!=-1){
    16             deal(x);  // 处理x
    17             x = scanner.nextInt();
    18         }
    19         System.out.println(Arrays.toString(heap));
    20     }
    21 
    22     /**
    23      * 如果数据量小于等于k,直接加入堆中
    24      * 等于k的时候,进行堆化
    25      * @param x
    26      */
    27     private static void deal(int x) {
    28         if (index<k) {
    29             heap[index++] = x;
    30             if (index==k) {
    31                 // 堆化
    32                 makeMinHeap(heap);
    33                 System.out.println(Arrays.toString(heap));
    34             }
    35         }else if (heap[0]<x) {
    36             heap[0] = x;
    37             MinHeapFixDown(heap, 0, k);
    38             System.out.println(Arrays.toString(heap));
    39         }else {
    40             System.out.println(Arrays.toString(heap));
    41         }
    42     }
    43     static void makeMinHeap(int[] A){
    44         int n = A.length;
    45         for(int i = n/2-1;i>=0;i--){
    46             MinHeapFixDown(A,i,n);
    47         }
    48     }
    49     
    50     private static void MinHeapFixDown(int[] A, int i, int n) {
    51         //  找到左右孩子
    52         int left = 2 * i + 1;
    53         int right = 2 * i + 2 ;
    54         // 左孩子已经越界,i就是叶子节点
    55         if (left>=n) {
    56             return ;
    57         }
    58         // min 指向了左右孩子中较小的那个
    59         int min = left;
    60         if (right>=n) {
    61             min = left;
    62         }else {
    63             if (A[right]<A[left]) {
    64                 min = right;
    65             }
    66         }
    67         // 如果A[i]比两个孩子都要小,不用调整
    68         if (A[i]<=A[min]) {
    69             return ;
    70         }
    71         // 否则,找到两个孩子中较小的,和i交换
    72         int temp = A[i];
    73         A[i] = A[min];
    74         A[min] = temp;
    75         // 小孩子那个位置的值发生了变化,i变更为小孩子那个位置,递归调整
    76         MinHeapFixDown(A, min, n);
    77     }
    78 
    79 }

    结果:

      

    总结:partition都能解决顺序统计量问题,堆更适用于海量数据流,适用于不能全部存储在内存中的数据,相当于实时数据流,而partition适用于能够一次加载到内存的数组。

  • 相关阅读:
    sql server 2008 r2安装详解 (转)
    SQL SERVER 与ORACLE常用函数比较(转)
    android色码对照表
    java小结
    如何查看android虚拟机的目录及文件
    java中的Serializable接口的作用
    android布局属性详解
    android 如何连接sqlserver数据库
    android 中Network error IOException: failed to connect to /127.0.0.1 (port 1433): connect failed: ECONNREFUSED (Connection refused)
    IDEA 将项目打包war包
  • 原文地址:https://www.cnblogs.com/xiaoyh/p/10290040.html
Copyright © 2020-2023  润新知