프로그래밍은 컴퓨터로 문제를 해결하는 것이다. 그렇다면 프로그래밍 능력은 “컴퓨터를 이용하여 얼마나 주어진 문제를 잘 해결하는가”에 달렸을 것이다. 프로그래밍을 잘하기 위한 요소는 무엇일까?
알고리즘은 컴퓨터 프로그래밍에서 가장 중요한 요소 중에 하나이다. 이는 프로그램의 성능 및 품질에 영향을 미치고, 좋은 알고리즘은 좀 더 빠른 시간 혹은 몇배는 빠른 시간안에 작동한다. 그렇다면 알고리즘은 무엇이고, 좋은 알고리즘은 어떻게 구분하는가?
이 글에서는 기본적인 알고리즘의 개념과 알고리즘 복잡도 분석 관련 내용을 정리해보았다.
Algorithm
컴퓨터로 주어진 문제를 풀기 위한 절차.
정의
- 입력 : 0개 이상의 입력이 존재하여야 한다.
- 출력 : 1개 이상의 출력이 존재하여야 한다.
- 명백성 : 각 명령어의 의미는 모호하지 않고 명확해야 한다.
- 유한성 : 한정된 수의 단계 후에는 반드시 종료되어야 한다.
- 유효성 : 각 명령어들은 실행 가능한 연산이여야 한다.
기술 방법
- 자연어(영어, 한국어 등등)
- 흐름도(Flow Chart)
- 유사 코드(pseudo-doce)
알고리즘 풀이 절차
파인만 알고리즘
- 칠판에 문제를 적는다.
- 골똘히 생각한다.
- 칠판에 답안을 적는다.
2번과 3번 사이에 대체 무슨일이 생겼는지 본인만 알듯하다..
일반적인 풀이 절차
- 문제를 읽고 이해한다.
- 문제를 익숙한 용어로 재정의한다.
- 어떻게 해결할지 계획을 세운다.
- 계획을 검증한다.
- 프로그램으로 구현한다.
- 어떻게 풀었는지 돌아보고, 개선할 방법이 있는지 찾아본다.
문제풀이를 위한 질문들
- 비슷한 문제를 풀어본 적이 있던가?
- 단순한 방법에서 시작할 수 있을까?
- 내가 문제를 푸는 과정을 수식화할 수 있을까?
- 문제를 단순화할 수 없을까?
- 그림으로 그려볼 수 있을까?
- 수식으로 표현할 수 있을까?
- 문제를 분해할 수 있을까?
- 뒤에서부터 생각해서 문제를 풀 수 있을까?
- 순서를 강제할 수 있을까?
- 특정 형태의 답만을 고려할 수 있을까?
자주하는 실수
- 산술 오버플로우
- 배열 범위 밖 원소에 접근
- 일관되지 않은 범위 표현 방식 사용
- Off-by-one 오류
- 컴파일러가 잡아주지 못하는 상수 오타
- 스택 오버플로우
- 다차원 배열 인덱스 순서 바꿔 쓰기
- 잘못된 비교 함수 작성
- 최소,최대 예외 잘못 다루기
- 연산자 우선순위 잘못 쓰기
- 너무 느린 입출력 방식 선택
- 변수 초기화 문제
- 실수값 처리
디버깅과 테스팅
디버깅
- 작은 입력으로 테스트
- 단정문 사용
- 계산 중간 결과 출력
테스팅
스캐폴딩
샘플 입력을 자동 생성하는 코드를 통하여 알고리즘 테스트
성능분석
필요성
- 처리할 데이터의 규모의 증가.
- 상용 프로그램의 메모리 사용량 증가.
측정방법
- 실행 시간 측정 방법(시간 복잡도)
- 동일한 조건에서 다른 알고리즘의 연산 시간 비교
- 사용 소프트웨어 환경, 똑같은 하드웨어 등 제약조건이 많음.
- T(N)을 비교 [입력값 $N$에 대한 시간 복잡도 함수]
- 기억 공간 분석(공간 복잡도)
- 알고리즘이 사용하는 기억 공간 분석.
- 보통 시간 복잡도 분석을 사용
- 특정 알고리즘이 수행하는 연산의 개수를 계산하여 알고리즘을 비교.
대부분 알고리즘이 차지하는 공간보다는 실행 시간에 더 관심이 많다.
빅오 표기법
- 일반적으로 입력의 개수 n과 시간 복잡도 함수 T(n)의 관계는 상당히 복잡함.
- 하지만, 자료의 개수가 많을 경우에는 차수가 가장 큰 항이 가장 영향을 크게 미치고 다른 항들은 상대적으로 무시될 수 있음.
증명
두개의 함수 $f(n)$과 $g(n)$이 주어졌을 때, 모든 $n>=n_0$에 대하여 $|f(n)|<=c|g(n)|$을 만족하는 2개의 상수 $C$와 $n_0$가 존재하면, $f(N)=O(g(N))$이다.
빅오 표기법에 따른 알고리즘의 실행 시간 비교
$O(1)< O(logN) < O(N) < O(NlogN) < O(N^2) < O (2^N) < O(N!)$
기타
- 빅 오메가 표기법, 빅 세타 표기법 등이 있지만, 빅 오 표기법을 주로 사용.
최선, 평균, 최악의 경우
- 최선 : 실행 시간의 가장 적은 경우를 고려
- 평균 : 평균 실행 시간을 고려
- 최악 : 실행 시간이 가장 오래 걸리는 경우를 고려
보통 최악의 경우를 알고리즘의 시간 복잡도 척도로 잡음. 계산이나 경우를 계산하였을 때 최악의 경우가 가장 합리적.
시간복잡도 분석
시간 복잡도(Time complexity)는 가정 널리 사용되는 알고리즘의 수행 시간
기준으로, 알고리즘이 실행되는 동안 수행하는 기본적인 연산의 수를 입력의 크기에 대한 함수
로 표현한 것.
선형 시간 알고리즘
$O(N)$
선형 이하 시간 알고리즘
이진 탐색
지수 시간 알고리즘
다항 시간 알고리즘
$O(N^k)$
$O(2^N)$
Problem | Number of iteration | Big $O$ |
---|---|---|
Moving average | $N$ | $O(N)$ |
Binary search | $logN$ | $O(logN)$ |
Set cover | $N \cdot M \cdot 2^M$ | $O(N \cdot M \cdot 2^M)$ |