Programming/Algorithm

[백준] 빠른 A+B (JAVA)

Supreme_YS 2021. 10. 20. 13:11
 

15552번: 빠른 A+B

첫 줄에 테스트케이스의 개수 T가 주어진다. T는 최대 1,000,000이다. 다음 T줄에는 각각 두 정수 A와 B가 주어진다. A와 B는 1 이상, 1,000 이하이다.

www.acmicpc.net


빠른 입력과 출력을 위해 BufferedReader와 BufferedWriter라는 것을 사용할 때가 있다. Input Data를 몇십만, 몇백만건씩 받을 때가 있는데, 기존에 사용하던 Scanner 나 System.out.print를 사용하면 시간초과가 발생할 수 있다. 이 사실을 기반으로 좀 더 코드를 살펴보기 위해 본 포스팅을 작성해보았다.

 

먼저, 각 메서드의 시스템 흐름도이다.

Scanner와 System.out.println의 시스템 흐름도 BufferedReader와 BufferedWriter의 시스템 흐름도
Scanner와 System.out.println의 흐름도

그림과 같이 중간에 과정이 추가되었는데 어떻게 연산 속도가 더 빠를 수 있는지 궁금해졌다. 이 부분에 대해 다양한 포스팅을 뒤적거렸다. 핵심은 디스크 I/O와 문맥 교환, 입출력은 생각보다 느리다는 생각부터 출발한다. 예로 키보드를 입력할 때마다 프로그램으로 전달이 된다면 오버헤드가 크게 발생한다. 따라서, 키보드 입력을 끝낸 뒤에 한 번에 전달되는 것이 훨씬 빠를 것이다. 마트에서 물건을 살 때 물건마다 진열대에서 계산대로 옮기는 것보다, 쇼핑카트에 담았다가 한 번에 계산대로 가져가는게 더 빠르다는 비유를 들 수 있을 것이다. 

 

하지만 BufferedReader에도 몇 가지 단점이 있다. 단점은 다음과 같다.

  • IOException의 예외처리가 필수적이다.
  • 입력받은 모든 데이터가 String으로 반환된다.
  • 줄마다 입력받아서, 따로 split하여 데이터를 처리해주어야 한다. 
  • 숫자형식으로 받기 위해서는 형변환이 필요하다.

Input Data에 1 2 3이 들어왔을 때 Scanner의 nextInt()로 받으면, [1, 2, 3]을 차례대로 받을 수 있다. 하지만 BufferedReader의 readLine()으로 받으면, "1 2 3"이라는 문자열 자체로 받으며, split(' ')로 띄어쓰기를 구분하여 Integer.parseInt() 과정이 필요해진다. 

 

위와 같은 지식을 기반으로 코드를 작성해보았다.

package Step3;

import java.io.*; // 1. import는 java.io.*로 한다. (Scanner는 java.util 클래스이다.)

public class BufferHap {
    public static void main(String[] args) throws IOException { // 2. main함수 우측에 throws IOException을 통해 예외를 처리한다.
        // 메소드 선언부에 throws를 명시하면, 해당 메소드 내에서 exception이 발생하는 경우 해당 메소드를 호출한 곳에서 예외가 발생한다.

        // 3. BufferedReader, BufferedWriter를 선언한다.
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        // 4. n을 입력받고, n만큼 loop를 돈다.
        int n = Integer.parseInt(bf.readLine());

        for (int i=0; i < n; i++){
            String s = bf.readLine(); // 4-1. 해당 줄 전체를 String으로 입력받아, 스페이스로 구분하여 형변환하여 덧셈을 수행한다.
            int a = Integer.parseInt(s.split(" ")[0]);
            int b = Integer.parseInt(s.split(" ")[1]);
            bw.write(a+b+"\n"); // 5. BufferedWriter에 써준다.

        }
        bw.flush();// 6. Buffer를 전송하고 Buffer를 비워준다.
    }
}

*여기서, bw.write()는 버퍼에 쓰는것이지, 화면에 출력되는 것이 아니다.  화면에 출력하는 역할은 bw.flush()가 수행한다. bw.flush()는 출력이 필요할 때 한 번만 수행해주면 된다. 만약 for문 안에 bw.flush()를 쓰면, 버퍼에 쓰고 바로 출력하므로 System.out.print와 다를바가 없다.고 한다. 

 

 

* Scanner vs Buffer

버퍼를 사용한 입력

 

'Programming > Algorithm' 카테고리의 다른 글

[백준] 2434번 : 별 찍기 - 1  (0) 2021.10.27
[백준] 3052번 : 나머지 (Java)  (0) 2021.10.27
선형 리스트 (Linear List)  (0) 2021.09.27
알고리즘의 개념  (0) 2021.09.27
자료구조의 개념  (0) 2021.09.27