• 10亿数中找出前1000大的数


    问题的提出:如何在10亿数中找出前1000大的数?

    解决方案:

      这是经典的TopN问题,先想到的时先排序,然后取前1000个数。部分排序,只排除前1000个数即可,但这两种方法的时间复杂度都比较高。

      分治法,类似快速排序中的epartition的操作,随机选一个数t,然后对整个数组进行partition,会得到两部分,前一部分的数都大于t,后一部分的数都小于t。

      如果说前一部分总数大于1000个,那就继续在前一部分进行partition寻找。如果前一部分的数小于1000个,那就在后一部分再进行partition,寻找剩下的数。

      分治法的时间复杂度为O(n)。首先,partition的过程,时间是o(n)。我们在进行第一次partition的时候需要花费n,第二次partition的时候,数据量减半了,所以只要花费n/2,同理第三次的时候只要花费n/4,以此类推。而n+n/2+n/4+...显然是小于2n的,所以这个方法的渐进时间只有o(n)。

    分治法的优化处理:

     1 import java.util.Arrays;
     2 
     3 public class TopN {
     4     // 父节点
     5     private int parent(int n) {
     6         return (n - 1) / 2;
     7     }
     8 
     9     // 左孩子
    10     private int left(int n) {
    11         return 2 * n + 1;
    12     }
    13 
    14     // 右孩子
    15     private int right(int n) {
    16         return 2 * n + 2;
    17     }
    18 
    19     // 构建堆
    20     private void buildHeap(int n, int[] data) {
    21         for(int i = 1; i < n; i++) {
    22             int t = i;
    23             // 调整堆
    24             while(t != 0 && data[parent(t)] > data[t]) {
    25                 int temp = data[t];
    26                 data[t] = data[parent(t)];
    27                 data[parent(t)] = temp;
    28                 t = parent(t);
    29             }
    30         }
    31     }
    32 
    33     // 调整data[i]
    34     private void adjust(int i, int n, int[] data) {
    35         if(data[i] <= data[0]) {
    36             return;
    37         }
    38         // 置换堆顶
    39         int temp = data[i];
    40         data[i] = data[0];
    41         data[0] = temp;
    42         // 调整堆顶
    43         int t = 0;
    44         while( (left(t) < n && data[t] > data[left(t)])
    45                 || (right(t) < n && data[t] > data[right(t)]) ) {
    46             if(right(t) < n && data[right(t)] < data[left(t)]) {
    47                 // 右孩子更小,置换右孩子
    48                 temp = data[t];
    49                 data[t] = data[right(t)];
    50                 data[right(t)] = temp;
    51                 t = right(t);
    52             } else {
    53                 // 否则置换左孩子
    54                 temp = data[t];
    55                 data[t] = data[left(t)];
    56                 data[left(t)] = temp;
    57                 t = left(t);
    58             }
    59         }
    60     }
    61 
    62     // 寻找topN,该方法改变data,将topN排到最前面
    63     public void findTopN(int n, int[] data) {
    64         // 先构建n个数的小顶堆
    65         buildHeap(n, data);
    66         // n往后的数进行调整
    67         for(int i = n; i < data.length; i++) {
    68             adjust(i, n, data);
    69         }
    70     }
    71 
    72     // 打印数组
    73     public void print(int[] data) {
    74         System.out.println(Arrays.toString(data));
    75     }
    76 }
     1 import java.util.Random;
     2 
     3 public class Main {
     4 
     5     public static void main(String[] args) {
     6 
     7         TopN topN = new TopN();
     8 
     9         // 第一组测试
    10         int[] arr1 = new int[]{56, 30, 71, 18, 29, 93, 44, 75, 20, 65, 68, 34};
    11 
    12         System.out.println("原数组:");
    13         topN.print(arr1);
    14         topN.findTopN(5, arr1);
    15         System.out.println("调整后数组:");
    16         topN.print(arr1);
    17 
    18         // 第二组测试
    19         int[] arr2 = new int[1000];
    20         for(int i=0; i<arr2.length; i++) {
    21             arr2[i] = i + 1;
    22         }
    23 
    24         System.out.println("原数组:");
    25         topN.print(arr2);
    26         topN.findTopN(50, arr2);
    27         System.out.println("调整后数组:");
    28         topN.print(arr2);
    29 
    30         // 第三组测试
    31         Random random =new Random();
    32         int[] arr3 = new int[1000];
    33         for(int i=0; i<arr3.length; i++) {
    34             arr3[i] = random.nextInt();
    35         }
    36 
    37         System.out.println("原数组:");
    38         topN.print(arr3);
    39         topN.findTopN(50, arr3);
    40         System.out.println("调整后数组:");
    41         topN.print(arr3);
    42     }
    43 }

    运行结果:

  • 相关阅读:
    POJ 2159 Ancient Cipher 难度:0
    POJ 3299 Humidex 难度:0
    POJ 1503 Integer Inquiry 大数 难度:0
    POJ 2262 Goldbach's Conjecture 数学常识 难度:0
    POJ 1083 Moving Tables 思路 难度:0
    PAT 甲级 1126 Eulerian Path
    Java 大数运算
    PAT 甲级 1010 Radix
    PAT 甲级 1137 Final Grading
    PAT 甲级 1064 Complete Binary Search Tree
  • 原文地址:https://www.cnblogs.com/zsh-blogs/p/10567803.html
Copyright © 2020-2023  润新知