Development Tip

Java의 System.in에서 읽는 가장 빠른 방법은 무엇입니까?

yourdevel 2020. 12. 8. 20:06
반응형

Java의 System.in에서 읽는 가장 빠른 방법은 무엇입니까?


나는 표준에서 공백이나 줄 바꿈으로 구분 된 정수 무리를 읽고 Scanner(System.in)있습니다.

Java에서이 작업을 수행하는 더 빠른 방법이 있습니까?


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 초에 내려받을 수),하지만 난 당신의 질문에 대답 한 나는 몇 가지 코드 골프 이것을 설정하지 않으려는 생각합니다.


Java의 스캐너처럼 작동하지만 속도면에서 여러 크기로 성능을 능가 하는 작은 InputReader 클래스를 만들었습니다. 사실 BufferedReader도 능가합니다. 다음은 표준 입력에서 다른 유형의 데이터를 읽는 데 만든 InputReader 클래스의 성능을 보여주는 막대 그래프입니다.

여기에 이미지 설명 입력

다음은 InputReader 클래스를 사용하여 System.in에서 오는 모든 숫자의 합계를 찾는 두 가지 방법입니다.

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) { }

경쟁 프로그래밍 관점에서 질문하는 경우 제출이 충분히 빠르지 않으면 TLE가됩니다.
그런 다음 System.in에서 String을 검색하기 위해 다음 메서드를 확인할 수 있습니다. 나는 자바 (경쟁 사이트)에서 최고의 코더 중 하나에서 가져 왔습니다.

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

당신은 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;
}

내 문제 에서이 코드는 약이었습니다. 을 (를) 사용 StringTokenizer하는 것보다 2 배 빠르며 이미 String.split(" "). (문제는 각각 최대 1 백만 개의 정수 1 백만 개를 읽는 것과 관련이 있습니다.)


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

프로그래밍 관점에서이 사용자 정의 된 스캔 및 인쇄 클래스는 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();
}

}

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

참고 URL : https://stackoverflow.com/questions/7049011/whats-the-fastest-way-to-read-from-system-in-in-java

반응형