⚡️알고리즘 풀이 속도 차이
백준에서 자바로 같은 문제를 풀어도 상위권 풀이들과 비교하면 3~4배의 속도 차이를 보인다.
이유는 간단했다.
나는 입력으로 Scanner를 상위권 풀이는 BufferedReader를 사용했다는 차이가 있다.
사소한 방법의 차이이지만 결과에선 큰 격차를 보이는 이 둘의 다른 점이 무엇인지 궁금해졌다.
⚡️Scanner와 BufferReader 차이
📌 Scanner
Scanner는 입력 받을 때 정수 값, 소수 값, 문자 데이터도 구분지어 읽어들일 수 있다.
즉 직관적이고 사용하기에 편리하다는 장점이 있다.
그렇지만 키보드의 입력이 키를 누르는 즉시 바로 전달되기 때문에 버퍼를 사용하는 BufferReader 보다
속도 면에서 불리하다는 큰 단점이 존재한다.
📌 BufferedReader
버퍼리더는 입력 받은 값을 기본적으로 8192 char (16384 byte) 크기의 버퍼에 담아두었다가 한번에 프로그램에 전송한다.
어쩌면 입력받은 즉시 전송하는 Scanner가 더 효율적이라고 생각될 수 있겠지만
버퍼링 없이 전송하는 것은 CPU와의 성능 차이 때문에 버퍼를 사용하는 방식보다 속도에서 비효율적이라고 할 수 있다.
과일을 수확할 때, 하나의 과일을 딸 때마다 창고로 옮겨주는 것과
수확한 과일을 한 수레에 모아 한번에 창고로 옮겨주는 것의 효율 차이를 예로 들 수 있다.
언어별 input method에 따른 속도를 보면 어떤 방식을 사용해 입력하는지,
왜 C와 C++이 빠른 속도를 보여주는지 알 수 있다.
⚡️BufferedReader 사용법
Scanner는 띄어쓰기와 개행문자를 기준으로 입력 값을 인식하기 때문에 따로 가공할 필요가 없지만
버퍼리더는 개행문자(엔터)만 경계로 인식하고 입력된 데이터의 형식이 String으로 고정되기 때문에 데이터를 따로 가공해주어야 한다.
BufferedReader와 StringTokenizer를 사용하기 위해 import를 해준다.
BufferedReader를 사용하기 위해선 예외처리가 필수적이기 때문에 try, catch문을 이용하던가
메인문 중괄호 시작 전 throws IOException 으로 처리해야만 한다.
입력을 받기 위해선 readLine() 메소드를 사용하고, 데이터가 문자 값으로 들어오기 때문에 숫자 값을 받아올 땐 꼭 형변환이 필요하다.
📌 다량의 데이터 입력 받기
단일 입력을 받을 때는 상관 없지만 다량의 데이터를 입력받을 때는 split 아니면 StringTokenizer를 사용해준다.
split은 입력 받는 동시에 별다른 처리 없이 배열로 데이터를 받아올 수 있다.
그에 반해 StringTokenizer의 경우 토큰화 된 문자열을 다시 처리해주어야 한다.
StringTokenizer의 생성자에서 추가적인 구분자를 명시하지 않을 경우 default 값은 띄어쓰기로 데이터가 구분되기 때문에
필요 시 다른 구분자를 사용할 경우 StringTokenizer st = new StringTokenizer(문자열, 구분자); 를 이용한다.
배열을 생성하며 크기를 정해줄 땐 countTokens() 메소드를 이용해 총 토큰의 수를 리턴 받는다.
그 다음 hasMoreTokens() 메소드가 토큰이 더이상 없을 때 false를 리턴 한다는 것을 이용해 while문을 돌리며 데이터를 저장한다.
성능면에선 split은 정규식을 기반으로 문자열을 자르는 로직으로 동작하기 때문에
단순히 공백 자리를 당겨서 채우는 StringTokenizer가 더 빠르다.
import java.io.*; //BufferedReader 사용
import java.util.*; //StringTokenizer 사용
public class BufferEx {
public static void main(String[] args) throws IOException { // 예외처리 필수
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 선언
String s = br.readLine();
System.out.println("String : " + s);
int i = Integer.parseInt(br.readLine()); // readLine()으로 받은 String 값을 int로 형변환
System.out.println("Int : " + i);
//여러 개의 데이터 입력받기
String s2[] = br.readLine().split(" "); //split을 이용해 다량의 데이터 입력 받기
StringTokenizer st = new StringTokenizer(br.readLine());
int arr[] = new int[st.countTokens()];
int count=0;
while(st.hasMoreTokens()) {
arr[count] = Integer.parseInt(st.nextToken());
System.out.println(arr[count++]);
//countTokens() : 총 토큰의 개수를 리턴
//hasMoreTokens() : 토큰이 남아있다면 true, 없으면 false 리턴
}
}
}
'Java, JSP' 카테고리의 다른 글
[Java/자바] interface 인터페이스 사용법 (0) | 2022.01.01 |
---|---|
[Java/자바] 추상메소드와 추상클래스 (0) | 2021.12.31 |
[Java/자바] final 의미와 사용법 (0) | 2021.12.30 |
[Java/자바] 다형성과 오버라이드, 캐스팅 (0) | 2021.12.29 |
[Java/자바] static 정적 변수와 메소드 (0) | 2021.12.23 |
댓글