从未知大小的输入读取数据子集:使用特定语法的内存使用情况。 (水库采样)

时间:2013-09-01 03:30:54

标签: java memory sampling

写这个:

N = args[1].split("\\s+").length;

使用命令行参数如:echo "A B C D E F G H I" | java Subset 3,如果我使用"A B C D E F G H I".split()字符串解析为字符串数组,它会消耗类似的内存吗?

我的说法是(作为挑战)学​​生(我)可以尝试从N字符串(N = 9,A到I)随机均匀地显示K个字符串(上面的cmd行中的K = 3) )输入,同时消耗与K成比例的内存,而不是N. 这基本上就是我想要做的事情。

编辑:mvp的回答很有帮助。现在更好地理解这个问题。

但是我觉得我应该补充说我只允许使用它:

private static Scanner scanner = new Scanner(new BufferedInputStream(System.in), charsetName);

我不能单独使用Scanner课程,或BufferedReader就此而言。鉴于这种限制,我有点不确定如何继续。

3 个答案:

答案 0 :(得分:2)

这可以解决未知长度的输入数据流(也就是说,我们仅停止EOF,并且不关心N是什么),并且将使用与K成比例的存储器。

首先,让我们解决K = 1。如果我们开始阅读输入流,我们应该假设第一个项目(在你的例子中是A)应该是我们的答案 - 因为如果没有输入,那一定是它。当我们阅读第二项时,我们应该考虑将其作为我们的答案,而不是A,概率为1/2。当我们阅读第3项C时,我们应该以概率1/3来看待它,依此类推。该算法将从输入流中随机选择1个项目,而不事先知道项目数量(每个项目具有相同的概率)。

对于K = 2,K = 3(或更多),我们采用类似的方法。例如,对于K = 3,请阅读3个项ABC并将其用作答案。当我们阅读第4项时,我们应该以{{1​​}}(K / N)的概率选择它,并用它来替换其中一个活动项,其概率为3/4。然后继续这样做直到输入流的EOF,最后打印3个活动项目。

答案 1 :(得分:1)

是的,它将使用相同的内容,因为String[]数组的创建始终是split数组,即使您没有明确地将其存储在任何位置。

我建议您按以下方式从输入中提取单词:

  1. 创建List wordList以存储3个字。
  2. 生成介于0和输入长度减去1之间的随机数。
  3. 如果对应于随机数的位置是空格,则生成新的随机数,直到该位置不是空格。
  4. 使用最后一个随机数作为起点,返回搜索空格或输入开头的输入。这个(+1)定义了一个单词的开头。
  5. 再次使用相同的随机数作为起始点,在输入中搜索空格或输入的结尾。这个(-1)定义一个单词的结尾。
  6. 如果此单词已在wordList中,则将其丢弃并从步骤2开始重复。
  7. 如果没有,请将其添加到列表中。
  8. 如果列表的大小小于3,也请从步骤2开始重复。
  9. 列印清单。
  10. 在此过程中,您只在内存中存储了3个字(K),而不是9(N)。

    扫描也可以通过以下方式进行:

        import java.util.Scanner;
    
        public class MyProgram {
            public static void main(String... args) {
                final int K= 3 ;
                String[] words= new String[K] ;
                int wordCount= 0 ;
                int nextWord= 0 ;
                Scanner scanner= new Scanner(System.in) ;
                while( scanner.hasNext() ) {
                    String word= scanner.next();
                    wordCount++;
                    if( nextWord < K ) {
                        words[nextWord]= word ;
                        nextWord++;
                    } else {
                        int replacePos= (int)(Math.random()*wordCount) ; 
                        if( replacePos < K ) {
                            words[replacePos]= word ;
                        }
                    }
                }
                scanner.close();
                for(String word: words ) {
                    System.out.println(word);
                }
            }
        }
    

答案 2 :(得分:1)

@mvp对于案例K = 1具有正确的解决方案,但是当K> 1时1取项目M的正确概率是K / M,而不是1 / M(在你的情况下,你应该选择概率为3/4的第4项,第5项概率为3/5,依此类推)。

顺便说一下,这被称为reservoir sampling