Python으로 알고리즘 공부하기 - 입출력

공부 시작 동기

얼마전 지인과 함께 알고리즘 공부를 위한 모각코를 시작했다 원래는 이전부터 알고리즘 공부는 시작했었다. 다만 오래가지 못해 그만두었다. 크게 흥미도 못느꼈고, 초기 계획도 너무 거창했기에 지금 당장 해야하는 일도 많은데 투자할 시간이 없다는 핑계로 하지 않았다.

알고리즘 공부를 처음 시작할 때, 대회 문제에 바로 뛰어들 수 있을줄 알았다. 김칫국을 항아리째 들이붓다가 현실을 마주했다. 우선 시작하는 방법을 모르겠다. input과 output이 나와있고, 문제도 어떤걸 요구하는지는 알겠는데 무슨 알고리즘을 써야하며, input은 어떻게 넣어야하며, output은 어떻게 출력해야하는지 전혀 모르겠다. 특히 입력에서 사용자 입력을 받겠다는 건지, input.txt 처럼 텍스트 파일을 읽어들이겠다는 건지 알려주는 사람이 하나도 없었다. 시작도 못하니 당연 흥미도 떨어져서 그만뒀다. (지금보면 혼자 시작해서 문제였던거 같기도 하다.)

다시 알고리즘 공부 필요성을 느끼게 된것은 취업 문제도 있지만, 요즘 내가 만들고 있는 코드가 마음에 안들었기 때문이다. 더 효율적으로, 더 빠르게 만들 수 있을거 같은데 그런 생각을 안하고 있었다. 개발자가 아닌 코더, 코딩하는 기계가 되는 기분이라 이 짓을 그만둬야겠다는 생각을 하게 되었다. 문제는 코딩 습관과 버릇이었다. 빠르게 프로토타입을 만들고 결과를 내야해서 무조건 하드코딩을 하고 있었다. 그러니 당연 느리고, 나중에 고치려면 유지보수도 되지 않아서 새로 만들 수 밖에 없었다. 그래서 코딩 습관을 효율적으로 코딩하는 습관으로 바꾸기로 했다. 간단하게 말해 자료구조와 알고리즘 사용을 버릇처럼 하기 위해서 알고리즘 공부를 시작했다. 서론이 길었지만 공부에는 동기와 목적이 매우 중요하다.

알고리즘 시작하기

1. 언어 선택하기

알고리즘 공부를 시작할 때, 제일 먼저 했던 일은 언어를 선택한 일이었다. 사실 알고리즘은 프로그램의 흐름을 이해하고 설계하는 것이 목적이기에 어떤 언어를 선택하건 크게 상관없다. 다만, 이왕 하는거 언어를 자유롭게 다룰 수 있는 능력까지 생기면 좋지 않은가? 그래서 이전부터 공부하고 싶었던 C와 C++을 알고리즘을 통해 새로 배우려 했다. 성능도 좋고, 다른 언어들보다 시스템 영역을 이해해야하는 언어이니 더 효율적으로 프로그램을 만들 수 있을거라 생각해서이다. 하지만 얼마 못가서 Python으로 돌아왔다. 그냥 진행하다가 “지금 쓰는 언어나 제대로 하고나서 다른 언어를 사용하자”는 생각이 들었다. 나름 Python을 계속 써왔지만, 어디가서 당당하게 “저 Python 할 줄 알아요!” 라고 말할 자신이 없었다. 그래서 결국은 Python 을 사용하기로 했다. C랑 C++은 결국 언어라 알고리즘에 익숙해지면 알아서 잘 하게 될거라 생각한다.

2. 입출력 방법

알고리즘 문제에서 입력은 어떻게 넣어주어야 할까?

혼자 알고리즘 공부를 시작할 때 가장 궁금했던 내용이다. 흔히 입력을 받는 방법은 3가지가 있다.

  • 사용자 입력
  • 파일 입출력
  • command-line arguments 입력

이 중 사용자가 입력하는 방식을 따른다고 생각하면 편하다. 채점 프로그램은 여러가지 입력 파일들이 있고, 이를 통해 테스트 하는 것 같다. 하지만 그렇다고 파일 입출력 방식을 이용하려면 ‘파일 경로’를 알아야하는데, 우리가 알리가 없다. arguments는 누가봐도 아닌거 같으니 넘어가자.

입력을 받아보자

Python에서 사용자 입력을 받는 방법은 input() 혹은 raw_input() 을 이용하는 것이다.

user_input = input()
# or
user_raw_input = raw_input()

하지만 이 방법은 알고리즘에서 사용하기에는 매우 느리다. 그래서 종종 채점중 시간 초과로 틀리는 경우가 생긴다. 입력이나 출력에서 시간을 차지하여 틀리는 경우만큼 어이없는 경우가 없다. 이를 방지하기 위해서는 다른 방법을 이용해야한다.

그래서 사용하는 방법이 sys.stdin.readline() 을 이용하는 방법이다.

import sys
# 입력이 문자열인 경우
string_input = sys.stdin.readline().rstrip()
# 입력이 정수인 경우
int_input = int(sys.stdin.readline())
# 입력이 문자열로 여러개인 경우
multi_string_input = sys.stdin.readline().rstrip().split(' ')
# 입력이 정수로 여러개인 경우 위 문자열을 다중으로 받은 리스트로 만든 후 이용
multi_int_input = [int(number) for number in multi_string_input]

여기에서 rstrip()readline()을 이용하면 개행문자(‘\n’)까지 String으로 들어오기에 버릇처럼 넣어주고있다. 입력이 숫자인 경우 바로 rstrip()을 제외하고 int()로 변환해도 문제없다. 입력이 한 줄에 여러개인 경우 split(' ')을 이용하면 받은 입력을 리스트로 저장할 수 있다.

Python뿐 아니라 다른 언어들도 마찬가지로 입출력이 빠른 방법이 있으니 각자에 맞는 방법을 찾아야한다. 참고로 성능 차이는 다음 그래프와 같으니 참고하자. 그래프를 보면 왜 알고리즘을 풀 때, 사람들이 Python을 사용하지 않는지 이해가 간다.

algorithm_input_performance 이미지 출처 : https://www.acmicpc.net/blog/view/56

그나저나 왜 둘은 성능 차이가 발생할까? 조사해보니 input() 은 Prompt를 이용하기 위한 과정이어서 디스플레이 하는 과정에서 일부 오버해드가 발생하는것 같다. 그래도 input()을 이용하면 개행문자(‘\n’)는 알아서 처리해주니, rstrip() 같은 귀찮은 작업은 제외해도 된다. 그리고 sys.stdin.readline()은 파일을 읽는 방식과 같다고 한다.

출력 해보자

Python을 이용할 때, 특별한 출력 방법은 없다. 평소 사용하던대로 print() 를 이용하면 된다. 출력 양식에만 맞게 잘 출력할 수 있도록 하자.

print(result)

추가로 출력이 여러개인 경우 된다면 오버헤드가 많은 print()를 이용하는 방법보다는 하나의 string 타입 변수에 묶어서 print()는 가능한 적게 사용하는 것이 좋다.

3. 문제 풀고 테스트 하기

문제를 풀었을 때, 맞는거 같다 싶으면 사실 그냥 제출하면 알아서 컴파일도 해주고, 입력도 넣어주고, 출력도 테스트 해준다. 심지어 Baekjoon 알고리즘 사이트는 컴파일 시 에러난 부분까지 알려준다. 하지만, 간단한 테스트를 위해 코드를 올리고 채점을 진행하기에는 불편하다. 그래서 로컬에서 입력 예시로 테스트 후에 출력을 확인하고 코드를 복사해서 제출하는 방식을 이용한다.

개발에 사용하는 운영체제는 macOS 또는 Linux Ubuntu를 이용하고 있어서 bash/shell을 이용하는 방식을 사용한다. Windows는 개발하기 불편해서 문서 작업, 게임 이외에는 잘 사용하지 않는 운영체제라 잘 모르겠다.(git bash를 이용하면 가능할지도?)

우선 문제를 해결하는 코드를 작성하고 파일로 저장한다. 그 후 터미널에서 echocat을 원하는 입력 값을 pipe로 넘겨주는 방식을 사용한다.

  • echo : 입력을 그대로 다시 출력해주는 명령어
  • cat : 파일의 내용을 출력해주는 명령어

두 명령어는 입력값의 형태에 따라 다르게 사용하면 된다. echo입력이 한 줄인 경우 사용하기 편하다.

user@host:~$ echo 입력값 | python 문제.py
출력 결과

cat입력이 여러줄로 이루어져 있는 경우, 입력을 input.txt 파일에 저장하고 사용하면 편하다.

user@host:~$ cat input.txt | python 문제.py
출력 결과

이제 알고리즘 문제를 풀기 위한 모든 준비가 끝났으니 공부를 시작해보자.


참고 자료