如何从数十亿的数字中有效地找到10个最大的数字?

时间:2017-01-15 07:38:05

标签: java arrays algorithm

问题陈述:从包含数十亿个数字的文件中查找10个最大数字

输入: 97911 98855 12345 78982 ..... .....

我实际上提出了以下具有

的解决方案
  • 最佳案例复杂度O(n) - 当文件的编号按降序排列时
  • 最坏情况复杂度O(n*10) ~ O(n)当文件按升序排列时
  • 平均 复杂度〜O(n)

在所有情况下,空间复杂度为O(1)

我正在使用文件阅读器和存储最多10个数字的已排序数组来读取文件。我将检查currentLine是否大于数组中的最小元素 - 如果是,将通过交换将其插入正确的位置。

Scanner sc = new Scanner(new FileReader(new File("demo.txt")));
int[] maxNum = new int[10];
    while(sc.hasNext()){
    int phoneNumber = Integer.parseInt(sc.nextLine());
    if(phoneNumber>maxNum[9]){
        maxNum[9] = phoneNumber;
        for(int i =9;i>0;i--){
            if(maxNum[i]>maxNum[i-1]){
                int temp = maxNum[i];
                maxNum[i] = maxNum[i-1];
                maxNum[i-1] = temp;
            }
        }
    }
    }

我正在寻找反馈,如果有更好的方法来实现这个

3 个答案:

答案 0 :(得分:4)

如果文件未排序,则必须至少查看文件中的每个数字一次,因为它可能是最大的10个。因此,O(n)是你能达到的最佳目标。

通过用最小堆替换maxNum数组,可以进行一些优化(但不会改变渐近复杂度)。如果要找到的数字数量足够大(比如说你正在寻找100个最大的数字),这将运行得更快。它可能还没有在10点获得回报。

答案 1 :(得分:2)

您可以使用多线程和并行化来改进算法。这意味着例如20个线程,并将文件分区为20个文件,并在每个部分中找到最大的10个数字。最后,在您维护的20个阵列(每个长度为10个)中找到最大的10个数字。

重点是操作是从文件或数据库中读取而不是写入。因此,应该可以通过不同的线程并行访问文件的不同部分。即使你的输入是在内存中,这比天真的搜索更快。这仍然是O(n),但是根据它们并行操作的线程数(例如 t ),它使用大约 n / t 比较。这意味着它比天真算法快 t 倍。

最后我应该说小阵列上的位优化作为主要时间是无用的,主要的一点是如何维护一个不保持小数组的大文件。

答案 2 :(得分:1)

一般来说,要找到N个数字中的K个最大数字:

  1. 按O(N lg N)时间对数字进行排序,然后取K最大值。如果磁盘上有数十亿个数字,则必须进行外部(磁盘上)排序,例如外部MergeSort。

  2. 使用容量为K的Min-Heap并扫描N个值。保持堆中的K最大值,其中最小的值位于顶部。运行时间:O(N lg K)。在扫描磁盘中的数字时,可以将最小堆保留在内存中。

  3. 使用选择算法在预期时间O(N)中找到第(N-K)个最大值。使用Quicksort分区算法的Quickselect算法也将对值进行分区,使得K个最大值位于第(N-K)个最大值的一侧。预计运行时间:O(N)。但是,该选择算法是在内存中。