Quando é necessário ler muito input

João Pedro Neto

Nós usamos a classe Scanner para ler o input dos problemas. O sua simplicidade é útil para escrevermos rapidamente esta parte da solução. No entanto, o desempenho do Scanner não é muito bom. Se for necessário ler muitos dados (por exemplo, 100.000 inteiros), corremos o risco de demorar demasiado, e não termos tempo para o cálculo da solução. O código seguinte pode ser-vos útil em situações dessas:


    import java.io.*;
    import java.util.*;

    /** Class for buffered reading int and double values
     *  Ref: https://www.cpe.ku.ac.th/~jim/java-io.html 
     */
    class Reader {
        static BufferedReader reader;
        static StringTokenizer tokenizer;

        /** call this method to initialize reader for InputStream */
        static void init(InputStream input) {
            reader = new BufferedReader( new InputStreamReader(input) );
            tokenizer = new StringTokenizer("");
        }

        /** get next word */
        static String next() throws IOException {
            while ( ! tokenizer.hasMoreTokens() ) {
                //TODO add check for eof if necessary
                tokenizer = new StringTokenizer( reader.readLine() );
            }
            return tokenizer.nextToken();
        }

        static int nextInt() throws IOException {
            return Integer.parseInt( next() );
        }
        
        static double nextDouble() throws IOException {
            return Double.parseDouble( next() );
        }
        
        // an example
        public static void main(String[] args) throws IOException {
            
            Reader.init( System.in );

            int n = Reader.nextInt();
            double x = Reader.nextDouble();
            
            System.out.printf("%d, %4.2f\n", n, x);
        }
    }

O Guilherme Espada fez um benchmark comparando o desempenho deste código vs. o do Scanner:


Benchmark             Mode  Cnt    Score    Error  Units
Main.measureReader   thrpt   20  349.466 ± 16.058  ops/s
Main.measureScanner  thrpt   20   39.809 ±  1.076  ops/s

Observamos que este método de leitura é cerca de nove vezes mais rápido que o Scanner!

Last modified: Friday, 23 September 2016, 8:50 PM