Какой самый быстрый способ прочитать из System.in в Java? - программирование
Подтвердить что ты не робот

Какой самый быстрый способ прочитать из System.in в Java?

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

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

4b9b3361

Ответ 1

Есть ли более быстрый способ сделать это в 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 секунды, но я думаю, что я ответил на ваш вопрос, и я не хотите превратить это в какой-нибудь гольф-код.

Ответ 2

Я создал небольшой класс InputReader, который работает так же, как Java Scanner, но превосходит его по скорости на многие величины, по сути, он превосходит 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) { }

Ответ 3

Если вы спросите с точки зрения конкурентного программирования, где, если представление недостаточно быстрое, это будет 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();
}'

Ответ 4

Вы можете читать от System.in в цифровом виде. Посмотрите на этот ответ: fooobar.com/questions/116472/....

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

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 миллиона каждый.)

Ответ 5

В перспективе программирования этот настраиваемый класс "Сканирование и печать" намного лучше, чем встроенные в 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();
}
}

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

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();
}

}

Ответ 6

Вы можете использовать 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);

Ответ 7

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

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

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()));
}