【问题标题】:optimization - converting std input to integer array in java优化 - 在 java 中将 std 输入转换为整数数组
【发布时间】:2016-09-04 03:58:31
【问题描述】:

我想读取输入的每一行,将数字存储在 int[] 数组中以进行一些计算,然后尽快进入下一行输入。

输入(标准输入)

2     4  8
15 10               5
12 14 3999 -284                      -71
0 -213 18 4 2
0

这是一个纯粹的优化问题,在现实世界中并不是完全好的做法,因为我假设输入完美。我对如何改进当前从标准输入获取输入并将其表示为整数数组的方法感兴趣。我见过使用扫描仪的方法,他们使用 getnextint 方法,但是我在多个地方阅读过扫描仪比 BufferedReader 慢得多。

这种输入步骤的吸收可以改进吗?

当前方法

BufferedReader bufferedInput = new BufferedReader(new InputStreamReader(System.in));
    String line;
    String[] lineArray;
    try{
        // a line with just "0" indicates end of std input
        while((line = bufferedInput.readLine()) != "0"){
            lineArray = line.split("\\s+"); // is "\\s+" the optimized regex
            int arrlength = lineArray.length;
            int[] lineInt = new int[arrlength];
            for(int i = 0; i < arrlength; i++){
                lineInt[i] = Integer.parseInt(lineArray[i]); 
            }
            // Preform some operations on lineInt, then regenerate a new   
            // lineInt with inputs from next line of stdin
        }
    }catch(IOException e){

    }

从其他问题来看Difference between parseInt and valueOf in java?parseint 似乎是将字符串转换为整数的最有效方法1。任何启示都会有很大帮助。

谢谢你:)

编辑 1:删除 GCD 信息和“算法”标签

编辑 2:(希望)使问题更简洁,语法修正

【问题讨论】:

  • 在这一行中 lineArray = line.split("\\s+") 正则表达式 \s+ 为每一行重新编译。要优化,请考虑逐字符处理字符串
  • 我不知道你到底想问什么。任何 GCD 算法都需要查看每个解析的整数,因此您无法避免解析输入中的每个整数。另外我希望 GCD 运行时主导解析时间,所以没有必要担心后者(这是你目前担心的——对吧?)
  • @j_random_hacker 以一种居高临下的方式我在问如何以这种形式(数字以空格分隔)从标准输入获取输入到整数数组,并且运行时间尽可能短。我想我会提供更多的背景背景。尽管 GCD 算法在运行时占主导地位,但我仍然希望我的解决方案的输入和显示输出部分尽可能快,注意这不是一个真实世界的例子,如果我的行话不正确,它更像是一个练习道歉我非常Java 和一般编程新手。
  • 提供一些额外的上下文有时会很好,但在这里我很困惑,因为您首先谈论 GCD,并使用了algorithm 标签,而 GCD 将(我确定)支配运行时间,所以很难说你真的只是在询问如何有效地读取整数数组。我建议删除所有与 GCD 相关的内容并删除 algorithm 标签(也不要太担心这一步需要多长时间:-)
  • @j_random_hacker 我知道说谢谢并不好,但是谢谢。我已经进行了编辑,现在问题应该更有意义/更简洁,即标准输入(以指示的格式)-> int [] 尽可能快。

标签: java arrays optimization stdin


【解决方案1】:

我赞同 Stephen 所说的,解析速度很可能大大超过实际 I/O 完成的速度,因此改进解析不会给你太多。

说真的,除非您已经构建了整个系统并对其进行了分析并发现低效的解析是导致其无法达到其性能目标的原因,否则请不要这样做。

严格来说只是作为一个练习,因为一般原则可能在其他地方有用,这里有一个如何直接从字符串解析它的示例。

假设是:

  1. 您将使用合理的编码,其中字符 0..9 是连续的。
  2. 流中的唯一字符是 0..9、减号和空格。
  3. 所有数字均格式正确。

另一个重要的警告是,为了简单起见,我使用了ArrayList,这对于存储原语来说是个坏主意,装箱/拆箱的开销可能会消除解析速度的所有改进。在现实世界中,我会使用list variant custom-made for primitives

public static List<Integer> parse(String s) {
    List<Integer> ret = new ArrayList<Integer>();

    int sign = 1;
    int current = 0;
    boolean inNumber = false;

    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (c >= '0' && c <= '9') { //we assume a sensible encoding
            current = current * 10 + sign * (c-'0');
            inNumber = true;
        }                       
        else if (c == ' ' && inNumber) {
                ret.add(current);
                current = 0;
                inNumber = false;
                sign = 1;;
        }               
        else if (c == '-') {
            sign = -1;
        }               
    }

    if (inNumber) {
        ret.add(current);
    }

    return ret;
}

【讨论】:

    【解决方案2】:

    首先,我只想指出,在您的特定示例中进行优化是完全没有意义的。

    对于您的示例,大多数人会同意 最佳 解决方案不是最佳解决方案。相反,最易读的解决方案将是最好的。


    话虽如此,如果你想要最优化的解决方案,那就不要使用Scanner,不要使用BufferedReader.readLine(),不要使用String.split,不要使用Integer.parseInt(...)

    改为使用BufferedReader.read() 一次读取一个字符,然后手动解析并将它们转换为int。您还需要实现自己的“int”类型的可扩展数组,其行为类似于ArrayList&lt;Integer&gt;

    这是很多(不必要的)工作,并且需要维护更多的代码行。坏主意...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-13
      • 1970-01-01
      • 1970-01-01
      • 2017-09-30
      • 1970-01-01
      • 2012-09-19
      • 2017-05-21
      • 2012-06-19
      相关资源
      最近更新 更多