반응형

Java Fast IO 코드 템플릿

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

public class main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(br.readLine());

        while(st.hasMoreTokens()){
            bw.write(Integer.parseInt(st.nextToken()) + " ");
        }
        
        //problem solve

        bw.flush();
        bw.close();
    }
}

java로 알고리즘 문제를 풀 때

입력의 개수가 엄청 많은 경우 Scanner을 사용하면 시간이 오래 걸려서

알고리즘을 잘 구현했더라도 시간 초과로 틀릴 수 있다.

 

java에서는 이를 해결하기 위해

BufferedReader, BufferedWriter을 이용하여 입력과 출력을 더 빠르게 할 수 있다.

이 방법이 Scanner을 이용해 입출력하는 것보다 빠른 이유는 다음과 같다.

 

Scanner을 이용하여 입출력할 때는 바로바로 입출력을 해서 io가 빈번하게 발생하는데,

Buffered 방식을 이용하면 입출력을 즉시 하는 것이 아니라 Buffered에 저장했다가 필요할 때 io를 실시하기 때문에

보다 적은 io횟수로 입출력을 할 수 있어서 보다 빠르게 작업을 수행할 수 있다.

 

더불어 내가 해야할 일 중 입력은 엄청 많은데 출력이 적은 경우

입력만 BufferedReader로 받고 출력을 System.out.println으로 간편하게 해도 되지 않나 하는 의문이 들었다.

입력과 출력을 완전히 분리해서 사용하면 크게 문제가 되지 않는 것 같다.

예를 들어 입력은 모두 BufferedReader을 사용해서 받고

출력은 System.out.println으로만 하면 정상적으로 작동한다.

 

하지만 만약에 System.out.println 과 bw.write()를 하나의 프로그램에서 둘다 사용한다면

내가 예상한 코드대로 동작하지 않는 경우가 생긴다.

즉 입력을 받을 때도 한가지 메소드를 이용해야하고,

출력을 할 때도 한가지 메소드만 출력해서 이용해야 두가지 메소드가 서로 얽히지 않는다.

 

 

 


 

 

System.out.println, BufferedWriter.write 소요시간 비교

실제로 두 방법의 소요시간 차이를 측정해보았다.

환경은 인텔리제이에서 돌리고, 숫자 100만개를 출력하는 속도를 비교해보았다.

 

먼저 BufferedWriter을 이용한 코드이다.

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

public class main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        //bw 사용
        long start = System.currentTimeMillis();
        for (int i=0; i<1000000; i++) {
            bw.write(i + " ");
        }
        bw.flush();
        long finish = System.currentTimeMillis();
        long bwTime = finish - start;
        bw.write("---------\n");
        bw.write("Buffered write 소요 시간 "+ bwTime);
        bw.close();
    }
}

Buffered Write 시간 테스트

 

 

이번엔 System.out.println 을 이용한 코드이다

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

public class main {
    public static void main(String[] args) throws IOException {
        //bw 사용
        long start = System.currentTimeMillis();
        int count = 0;
        for (int i=0; i<1000000; i++) {
            System.out.print(i + " ");
        }
        long finish = System.currentTimeMillis();
        long sysTime = finish - start;

        System.out.println("---------\n");
        System.out.println("System out 소요 시간 "+ sysTime);

    }
}

System.out.println 소요 시간

 

같은 출력을 할 때

Buffered 방식을 이용하면 85ms,

System.out.print 방식을 이용하면 1171ms가 소요된 것을 알 수 있다.

입출력하는 데이터의 크기가 더 커질수록 두 방식의 시간차이는 더 커질 것이다.

 

 

 


 

반드시 Fastio로 문제를 풀어야 하는가?

하지만 꼭 모든 알고리즘 문제에 fastio를 적용해야하는 건 아니다.

입출력의 개수가 작은 편이라면

대부분 System 방식을 사용해서 간편하게 문제를 풀어도 해결할 수 있다.

 

이는 정확히 측정한 것이 아니고 문제마다 걸려있는 시간 제한에 따라 다르지만

내 개인적인 체감 상 데이터의 크기 N이 10,000개 이하정도라면

Buffered까지 사용하지 않고 System만을 이용해서도 문제를 해결할 수 있는 것 같다.

다만 Buffered를 이용해서 푼거에 비해 소요 시간이 많게 나올 수 있다.

 

알고리즘 문제를 푸는데 자바 입출력 속도를 위해 Buffered와 StringTokenizer 을 써서 코드를 여러줄 쓴다는 게

꽤 귀찮게 느껴지는 일이긴 하다.

 

상황에 따라 유동적으로 쓸 수 있도록 훈련하면 좋을 것 같다.

+ Recent posts