问题陈述:从包含数十亿个数字的文件中查找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;
}
}
}
}
我正在寻找反馈,如果有更好的方法来实现这个
答案 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个最大数字:
按O(N lg N)时间对数字进行排序,然后取K最大值。如果磁盘上有数十亿个数字,则必须进行外部(磁盘上)排序,例如外部MergeSort。
使用容量为K的Min-Heap并扫描N个值。保持堆中的K最大值,其中最小的值位于顶部。运行时间:O(N lg K)。在扫描磁盘中的数字时,可以将最小堆保留在内存中。
使用选择算法在预期时间O(N)中找到第(N-K)个最大值。使用Quicksort分区算法的Quickselect算法也将对值进行分区,使得K个最大值位于第(N-K)个最大值的一侧。预计运行时间:O(N)。但是,该选择算法是在内存中。