【问题标题】:Faster implementation of more than one input in a single line (Java)在一行中更快地实现多个输入 (Java)
【发布时间】:2012-03-26 10:00:42
【问题描述】:

好吧,这可能是一个愚蠢的问题。

我只想更快地解决以下问题

我想在一行中输入三个整数,例如:

10 34 54

一种方法是制作一个 BufferedReader 然后使用 readLine() 它将整行读取为字符串 然后我们可以使用 StringTokenizer 来分隔三个整数。 (实施缓慢)

另一种方法是使用“扫描仪”并通过 nextInt() 方法获取输入。 (比以前的方法慢)

我想要一个快速的实现来接受这种类型的输入,因为我必须阅读超过 2,000,000 行并且这些实现非常慢。

我的实现:

BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

for(i=0;i<n;i++) {
    str=br.readLine();
    st = new StringTokenizer(str);
    t1=Integer.parseInt(st.nextElement().toString());
    t2=Integer.parseInt(st.nextElement().toString());
    z=Long.parseLong(st.nextElement().toString());
}

这个循环了n次。 ( n 是条目数) 由于我知道每一行将只包含三个整数,因此无需检查 hasMoreElements()

【问题讨论】:

  • 有多慢?您能否发布一些您使用的示例代码以及时间?
  • 您可以使用 BufferedReader 并进行自己的解析,专门收集 N 个字符,直到您看到一个空白或字符串的结尾。这可能会更快。请注意,通过使用 BufferedReader 和更大的缓冲区(10kB 已经有很大帮助),您将在所有情况下获得更好的性能。
  • @SteveMcLeod 我在一个编程网站上使用了这种方法,但超出了时间限制。所以我认为会有更好的方法来做到这一点。
  • 读取 > 200k 文本行并从中解析出三个整数总是不太理想。最好只执行一次,然后存储数据的二进制(流?)版本,并在下次使用。
  • @TheBlastOne 你能提供一个示例实现吗?我想你问错了。每行包含三个整数。

标签: java input


【解决方案1】:

我只想更快地解决以下问题。

您可能不需要更快的实施。严重地。即使是 200 万行的输入文件。

机会是:

  • 处理文件的时间多于读取文件的时间,并且
  • 大部分“读取时间”用于在操作系统级别做事,或者只是等待读取下一个磁盘块。

我的建议是不要费心优化这个除非整个应用程序运行时间过长。当您发现这种情况时,请分析应用程序,并使用分析统计信息告诉您哪些地方值得花精力进行优化。

(我的直觉是优化应用程序的这一部分并没有什么好处。但不要依赖它。分析它!)

【讨论】:

    【解决方案2】:

    这是一个非常快的基本示例:

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader("myfile.txt"));
        String line;
        while ((line = reader.readLine()) != null) {
            for (String s : line.split(" ")) {
                final int i = Integer.parseInt(s);
                // do something with i...
            }
        }
        reader.close();
    }
    

    但是,您的任务基本上需要时间。

    如果您在网站上执行此操作并达到超时,您应该考虑在后台线程中执行此操作,并向用户发送响应,说明正在处理数据。您可能需要为用户添加一种检查进度的方法。

    【讨论】:

    • 会试试这个。但我认为它将提供与 StringTokenizer 相似的时间。编程网站是指编程竞赛(类似于 TopCoder)。
    • @Android 大声笑...来吧,发布您的代码和计时结果,我们会看到我们能为您做些什么。对我们来说,其他一切都是在黑暗中拍摄,浪费时间。
    • 另外,Integer.parseInt 将很难用更高效和可读的东西来代替。这可能是“字符串到数字的转换不是微不足道的并且需要相当一段时间”低估的情况。 IE。可能是字符串拆分(或扫描仪使用)不是这里最大的性能差距。
    【解决方案3】:

    这就是我所说的“专业扫描仪”的意思。根据解析器(或拆分)的效率,这可能会更快一些(可能不是):

    BufferedReader br=new BufferedReader(...);  
    for(i=0;i<n;i++) 
    {     
        String str=br.readLine();
        long[] resultLongs = {-1,-1,-1};
        int startPos=0;
        int nextLongIndex=0;
        for (int p=0;p<str.length();p++)
        {
            if (str.charAt(p)== ' ')
            {
                String intAsStr=str.substring(startPos, p-1);
                resultLongs[nextLongIndex++]=Integer.parseInt(intAsStr);
                startpos=p+1;
            }
        }
        // t1, t2 and z are in resultLongs[0] through resultLongs[2]     
        }
    

    Hths.

    当然,如果输入文件包含垃圾,即除 long 之外的任何其他内容,用空格分隔,这将失败。

    此外,为了尽量减少到操作系统的“往返”,最好为缓冲读取器提供非标准(大于标准)缓冲区。

    我在评论中提炼的另一个提示:如果您必须多次阅读如此巨大的文本文件,即在更新后多次阅读,您可以将所有 long 读入数据结构(可能是 List包含三个 long 的元素),并将其流式传输到“缓存”文件中。下一次,将文本文件的时间戳与“缓存”文件的时间戳进行比较。如果它较旧,请读取缓存文件。由于流 I/O 不会将 long 序列化为其字符串表示形式,因此您会看到更好的读取时间。

    编辑:错过了 startPos 重新分配。 EDIT2:添加了缓存思路说明。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-18
      • 2020-03-09
      • 2010-12-17
      • 2014-03-11
      • 2019-07-24
      • 1970-01-01
      • 2021-01-09
      相关资源
      最近更新 更多