Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何有效地从数十亿个数字中找出10个最大的数字?_Java_Arrays_Algorithm - Fatal编程技术网

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

Java 如何有效地从数十亿个数字中找出10个最大的数字?,java,arrays,algorithm,Java,Arrays,Algorithm,问题陈述:从包含数十亿个数字的文件中最多查找10个数字 输入: 97911 98855 12345 78982 ..... …. 我实际上想出了下面的解决方案 最佳案例复杂性O(n)-当文件中的数字按降序排列时 当文件的数字按升序排列时,最坏情况的复杂性O(n*10)~O(n) 平均值 复杂性~O(n) 在所有情况下,空间复杂度都是O(1) 我正在使用文件读取器和存储最多10个数字的排序数组读取文件。我将检查currentLine是否大于数组中的最小元素-如果大于,将通过交换将其插入正确的位

问题陈述:从包含数十亿个数字的文件中最多查找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;
            }
        }
    }
    }

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

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


通过使用最小堆替换
maxNum
数组,可以进行一些优化(但是不改变渐进复杂性)。如果要查找的数字的计数足够大(假设您正在查找最大的100个数字),则运行速度会更快。在10时可能还没有回报。

一般来说,从N个数中找出K个最大数:

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

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

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


  • 您可以通过多线程和并行化来改进算法。这意味着运行20个线程,将文件划分为20个文件,并在每个部分找到最大的10个数字。最后,在您维护的20个数组(每个数组的长度为10)中找出最大的10个数

    关键是操作是从文件或数据库中读取,而不是写入。因此,应该可以通过不同的线程并行访问文件的不同部分。即使您的输入在内存中,这也比单纯的搜索快。这仍然是O(n),但取决于它们并行运行的线程数(比如t),它使用大约n/t比较。这意味着它比一个简单的算法快约t倍


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

    FYR,
    O(n*10)
    O(n)
    相同。您可以使用内置方法来查找最大值,每当找到最大值时,请存储该值,然后将其删除,然后再执行10次。@Null。你建议采用哪种内置方法。。它是否不需要多次传递和更多的迭代检查,它将帮助您。值是否有上限?是的,如果所需的最大数更多,这是真的。。但是对于10个数字,正如您所说的,数组会快得多。我看不出有任何理由不在这里使用
    min heap
    ,这种实现在交换操作方面有更多的成本,不需要将它们按顺序排列,只需在从堆顶部轮询时执行一次即可。@Xlee。当然将运行一些基线测试并查看差异。答案只是说OP正在做的是好的,而不是。在最好的情况下,它可以是一个评论。事实上,这个答案应该删除。@SaeedAmiri显然,我有不同的观点。对于单线程解决方案,OP接近最佳值。正如你所建议的,使用并行处理可以归结为“购买一台功能更强大的机器”,正是因为这个原因,它的速度更快。答案是缺少处理大文件的主要内容,而是提供了一些类似维基百科的信息。这些只是一般信息。@SaeedAmiri:在这三点中,我都清楚地提到了如何将算法应用于磁盘上的大数据。我的意思是,主要的一点是并行执行,而不仅仅是noraml顺序执行。@SaeedAmiri:在OP的帖子中,他在哪里说他有多台计算机用于并行?并行性不应该是首要考虑的问题。创建数据无法放入内存的算法更为重要。OP不需要说,你应该醒悟,现在不是1970年,即使手机有多处理器。你只是重复了1970年的教科书。阅读我对另一个答案的评论。