Какой самый быстрый способ чтения из System.in на Java? - PullRequest
58 голосов
/ 13 августа 2011

Я читаю группу целых чисел, разделенных пробелом или символами новой строки из стандарта при использовании Scanner(System.in).

Есть ли более быстрый способ сделать это в Java?

Ответы [ 7 ]

84 голосов
/ 13 августа 2011

Есть ли более быстрый способ сделать это в Java?

Да. Сканер работает довольно медленно (по крайней мере, по моему опыту).

Если вам не нужно проверять ввод, я предлагаю вам просто обернуть поток в BufferedInputStream и использовать что-то вроде String.split / Integer.parseInt.


Небольшое сравнение:

Чтение 17 мегабайт (4233600 номеров) с использованием этого кода

Scanner scanner = new Scanner(System.in);
while (scanner.hasNext())
    sum += scanner.nextInt();

взял на мою машину 3,3 секунды . пока этот фрагмент

BufferedReader bi = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = bi.readLine()) != null)
    for (String numStr: line.split("\\s"))
        sum += Integer.parseInt(numStr);

заняло 0,7 секунд .

Путем дальнейшего недоразумения в коде (перебирая line с String.indexOf / String.substring), вы можете довольно легко сократить его до 0,1 секунды, но я думаю, что я ответил на ваш вопрос, и я не хочу превратить это в какой-то код гольф.

3 голосов
/ 07 марта 2019

Если вы спрашиваете с точки зрения конкурентного программирования, где, если представление недостаточно быстрое, это будет TLE. Затем вы можете проверить следующий метод для извлечения String из System.in. Я взял у одного из лучших кодеров в Java (конкурентные сайты)

private String ns()
{
    int b = skip();
    StringBuilder sb = new StringBuilder();
    while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
        sb.appendCodePoint(b);
        b = readByte();
    }
    return sb.toString();
}`
3 голосов
/ 27 апреля 2017

Я создал небольшой класс InputReader , который работает так же, как сканер Java, но превосходит его по скорости на многие величины, фактически он также превосходит BufferedReader.Вот гистограмма, которая показывает производительность класса InputReader, который я создал для чтения различных типов данных из стандартного ввода:способы нахождения суммы всех чисел из System.in с использованием класса InputReader:

int sum = 0;
InputReader in = new InputReader(System.in);

// Approach #1
try {

    // Read all strings and then parse them to integers (this is much slower than the next method).
    String strNum = null;
    while( (strNum = in.nextString()) != null )
        sum += Integer.parseInt(strNum);

} catch (IOException e) { }

// Approach #2
try {

    // Read all the integers in the stream and stop once an IOException is thrown
    while( true ) sum += in.nextInt();

} catch (IOException e) { }
1 голос
/ 26 мая 2019

StringTokenizer - это намного более быстрый способ чтения ввода строки, разделенного токенами.

Проверьте приведенный ниже пример, чтобы прочитать строку целых чисел, разделенных пробелом, и сохранить в массиве,

String str = input.readLine(); //read string of integers using BufferedReader e.g. "1 2 3 4"
List<Integer> list = new ArrayList<>();
StringTokenizer st = new StringTokenizer(str, " ");
while (st.hasMoreTokens()) {
    list.add(Integer.parseInt(st.nextToken()));
} 
1 голос
/ 01 марта 2017

Вы можете читать с System.in цифрой за цифрой. Посмотрите на этот ответ: https://stackoverflow.com/a/2698772/3307066.

Я копирую код здесь (едва модифицированный). По сути, он читает целые числа, разделенные всем, что не является цифрой. (Авторы оригинала.)

private static int readInt() throws IOException {
    int ret = 0;
    boolean dig = false;
    for (int c = 0; (c = System.in.read()) != -1; ) {
        if (c >= '0' && c <= '9') {
            dig = true;
            ret = ret * 10 + c - '0';
        } else if (dig) break;
    }
    return ret;
}

В моей задаче этот код был ок. В 2 раза быстрее, чем при использовании StringTokenizer, который был уже быстрее, чем String.split(" "). (Проблема заключалась в чтении 1 миллиона целых чисел до 1 миллиона каждый.)

0 голосов
/ 14 октября 2018

Вы можете использовать BufferedReader для чтения данных

BufferedReader inp = new BufferedReader(new InputStreamReader(System.in));
  int t = Integer.parseInt(inp.readLine());
  while(t-->0){
    int n = Integer.parseInt(inp.readLine());
    int[] arr = new int[n];
    String line = inp.readLine();
    String[] str = line.trim().split("\\s+");
    for(int i=0;i<n;i++){
      arr[i] = Integer.parseInt(str[i]);
    }

А для печати используйте StringBuffer

    StringBuffer sb = new StringBuffer();
    for(int i=0;i<n;i++){
              sb.append(arr[i]+" "); 
            }
    System.out.println(sb);
0 голосов
/ 21 апреля 2018

С точки зрения программирования этот настраиваемый класс Scan and Print намного лучше, чем встроенные классы Java Scanner и BufferedReader.

import java.io.InputStream;
import java.util.InputMismatchException;
import java.io.IOException;

public class Scan
{

private byte[] buf = new byte[1024];

private int total;
private int index;
private InputStream in;

public Scan()
{
    in = System.in;
}

public int scan() throws IOException
{

    if(total < 0)
        throw new InputMismatchException();

    if(index >= total)
    {
        index = 0;
        total = in.read(buf);
        if(total <= 0)
            return -1;
    }

    return buf[index++];
}


public int scanInt() throws IOException
{

    int integer = 0;

    int n = scan();

    while(isWhiteSpace(n))   /*  remove starting white spaces   */
        n = scan();

    int neg = 1;
    if(n == '-')
    {
        neg = -1;
        n = scan();
    }

    while(!isWhiteSpace(n))
    {

        if(n >= '0' && n <= '9')
        {
            integer *= 10;
            integer += n-'0';
            n = scan();
        }
        else
            throw new InputMismatchException();
    }

    return neg*integer;
}


public String scanString()throws IOException
{
    StringBuilder sb = new StringBuilder();

    int n = scan();

    while(isWhiteSpace(n))
        n = scan();

    while(!isWhiteSpace(n))
    {
        sb.append((char)n);
        n = scan();
    }

    return sb.toString();
}


public double scanDouble()throws IOException
{
    double doub=0;
    int n=scan();
    while(isWhiteSpace(n))
    n=scan();
    int neg=1;
    if(n=='-')
    {
        neg=-1;
        n=scan();
    }
    while(!isWhiteSpace(n)&& n != '.')
    {
        if(n>='0'&&n<='9')
        {
            doub*=10;
            doub+=n-'0';
            n=scan();
        }
        else throw new InputMismatchException();
    }
    if(n=='.')
    {
        n=scan();
        double temp=1;
        while(!isWhiteSpace(n))
        {
            if(n>='0'&&n<='9')
            {
                temp/=10;
                doub+=(n-'0')*temp;
                n=scan();
            }
            else throw new InputMismatchException();
        }
    }
    return doub*neg;
}

public boolean isWhiteSpace(int n)
{
    if(n == ' ' || n == '\n' || n == '\r' || n == '\t' || n == -1)
        return true;

    return false;
}

public void close()throws IOException
{
    in.close();
}
}

И настроенный класс печати может быть следующим:

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class Print
{
private BufferedWriter bw;

public Print()
{
    this.bw = new BufferedWriter(new OutputStreamWriter(System.out));
}


public void print(Object object)throws IOException
{
    bw.append("" + object);
}

public void println(Object object)throws IOException
{
    print(object);
    bw.append("\n");
}


public void close()throws IOException
{
    bw.close();
}

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...