반응형

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 을 써서 코드를 여러줄 쓴다는 게

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

 

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

반응형

인텔리제이에서 vscode의 Ctrl + D (같은 단어 선택) 기능 KeyMap에서 찾기

 

vscode를 이용할 때 같은 단어를 여러개 선택하려면 ctrl+d 키를 여러번 누르면 된다.

인텔리제이에서도 동일한 기능이 존재했다.

다만 인텔리제이 버전이나 운영체제(윈도우, 맥, 리눅스)에 따라 단축키가 다르게 설정되어 있어

이를 편하게 이용하려면 변경이 필요하다.

 

많은 블로그의 글에서 단축키를 알려주지만 해당 단축키를 KeyMap에서 찾는 기능은

잘 소개를 안해주는 것 같아서 글을 쓴다.

 

 

 


 

 

 

Add Selection for Next Occurence

인텔리제이에서 vscode ctrl+d 의 단축키 기능의 이름은

'Add Selection for Next Occurence' 이다.

해당 기능의 단축키를 변경하기 위해

 

인텔리제이 메뉴에서

File -> Settings -> KeyMap으로 이동해서

검색창에 occur을 검색해서 'Add Selection for Next Occurence' 를 찾아

우클릭하여 keyboard shortcut 을 추가해주면 단축키가 설정된다.

만약 나처럼 ctrl+d를 단축키로 이용하려면

이미 인텔리제이에서는 ctrl+d가 다른 기능으로 맵핑되어 있기 때문에

이미 맵핑되어 있는 기능을 다 제거해주어야 한다.

위와 같은 warning 문구가 나타나면 remove를 해야

 

내가 새로 설정한 키로 기능을 올바르게 이용할 수 있다.

 

 

 

 

 

 

Add Selection for Next Occurence와 유사한 단축키 설명

https://blog.jetbrains.com/idea/2014/03/intellij-idea-13-1-rc-introduces-sublime-text-style-multiple-selections/

 

IntelliJ IDEA 13.1 RC Introduces Sublime Text Style Multiple Selections | The IntelliJ IDEA Blog

We have two exciting pieces of news for you today.First of all, IntelliJ IDEA 13.1 RC is now available for download, so you can try all the new features right away. By the way, this is the last chan

blog.jetbrains.com

 

반응형

키보드 입력기

평상시에 잘 되던 이클립스 자동정렬 Ctrl + Shift + F 나

주석 Ctrl + Shift  + '/' 같은 이클립스 단축키가 안되서 찾아보니까

 

키보드가 한컴입력기로 되어있으면 이클립스가 인식을 못하는 거였습니다..

 

제어판 -> 언어 -> 키보드에서 Microsoft 입력기로 바꾸면

 

이클립스의 모든 단축키를 정상적으로 이용할 수 있습니다.

 

반응형

1. 추상 클래스 상속

abstract class Shape{
	public Shape(){}
    public void Paint(){draw();}
    abstract public void draw(); // 추상 메소드
}

abstract class Line extends Shape{ //추상 메소드 draw()를 상속 받았는데 구현을 하지 않으면 sub class 역시 추상 클래스가 된다
	public String toString(){
    	return "Line";
    }
}

자바에서 슈퍼클래스의 추상 메소드를 서브 클래스에서 구현하지 않으면,

서브 클래스 역시 슈퍼 클래스처럼 abstract 클래스가 된다.

 

적절한 비유는 아니지만

abstract를 빚으로 생각한다면

부모 클래스에 있는 abstract(빚) 메소드를 자식이 해결하지 못한다면

자식도 abstract class가 되어버린다.

(abstract class면 객체를 생성할 수 없다..) 

 

 

2. 추상 클래스 사용 이유

서브 클래스마다 다르게 구현해야 할 필요가 있는 메소드를 추상 메소드로 정의해준다.

abstract class Animal{
	abstract void bark();
}

class dog extends Animal{
	void bark(){
    	System.out.println("멍멍");
    }
}

class cat extends Animal{
	void bark(){
    	System.out.println("냐옹");
    }
}

class bird extends Animal{
	void bark(){
    	System.out.println("짹쨱");
    }
}

이런 느낌이다.

큰 프로그램의 객체지향 설계를 해줄 때 서브 클래스의 세부 내용을 각각 다르게 해주어야 할 경우

이런 식으로 추상 메소드를 이용해주면 깔끔하게 코드를 정리할 수 있다.

+ Recent posts