점근 표기법(asymptotic notation)은 어떤 함수의 증가 양상을 다른 함수와의 비교로 표현하는 수론과 해석학의 방법이다. 알고리즘의 복잡도를 단순화할 때나 무한급수의 뒷부분을 간소화할 때 쓰인다. 이 중 압도적으로 많이 쓰이는 것이 대문자 O 표기법, Big-O 표기법이다. 이 Big-O 표기법은 계수와 낮은 차수의 항을 제외시키는 방법이다.
점근 표기법의 세가지 방법
Big-O 표기법은 점근 표기법 중 가장 많이 사용되는 표기법으로 알고리즘의 효율성을 분석할때 사용한다.
Big-O 표기법을 사용하는 이유
는, 평균을 나타내는 세타 표기법이 가장 이상적이고 정확하지만, 도출하기가 상대적으로 어려워서 알고리즘의 최악의 경우를 판단하면 평균과 가까운 성능으로 예측이 가능하여 Big-O 표기법을 사용한다.
이러한 Big-O 표기법은 아래와 같이 계수항과 낮은 차수 항을 제외 시키는 방법이다.
O(3N) > O(N)
O(N²+2N) > O(N²)
O(1) < O(log n) < O(n) < O(n * log n) < O(n²) < O(n³) < O(2^n) < O(n!)
아래는 Big-O의 복잡도를 나타내는 표이다.
이러한 Big-O 표기법에는 시간복잡도
와 공간복잡도
가 존재한다.
시간복잡도
는 알고리즘의 속도에 해당하는 연산시간의 분석결과이다.
시간 복잡도
는 연산 수행에 어떤 고정된 시간이 걸릴 때, 알고리즘에 의해서 수행되는 기본 연산의 개수를 세어 예측할 수 있다.
아래 자바 예제를 통해서 알아보자.
만약, 입력 N에 대해서 N²을 구하는 함수를 작성한다고 하면, 아래와 같이 여러가지 방법이 있고 각각의 시간복잡도는 다르다.
// 곱셈 연산을 1개 사용하므로 O(1)
int multiple(int N){
return N*N;
}
// 덧셈 연산 1개와 대입 연산 1개가 N번씩 실행되므로 O(2N) > O(N)
int multiple2(int N) {
sum = 0;
for(int i = 1 ; i < = N; i++{
sum += N;
}
return sum;
}
// 덧셈 연산 1개와 곱셈 연산 1개가 N번씩 성립되므로 2N > 그 2N연산이 N번 실행되므로
// O(2N²) > O(N²)
int multiple3(int N){
sum = 0;
for(int i = 1; i <= N; i++){
for(int j = 1; j <= N; j++){
sum += 1;
}
}
return sum;
}
공간복잡도
는 알고리즘을 사용할 때 메모리 사용량을 나타낸다.
만약 크기가 N인 배열을 만들면 공간 복잡도가 O(N)이 되고, N²인 배열을 만들면 O(N²)이 된다.
재귀 함수 호출의 경우 스택 공간을 고려 해야 한다.
1부터 N까지의 합을 구하는 예제를 재귀를 통해 구현 하면 아래와 같이 공간 복잡도가 O(N)이 된다.
// N = 3일때 스택에 쌓이는 메모리는 sum(1) + sum(2) + sum(3), 공간 복잡도가 O(N)이다.
int sum(int N){
sum = 0;
if(N<1)
return 0;
return N + sum(N-1);
}
하지만 N번의 호출이더라도 아래와 같이 호출하면 공간 복잡도가 O(1)이 된다.
// mainSum에서 N번 sum을 호출하지만 for문 안에서
// sum(i, i+1)의 값을 주어지며 스택안에서 계산되어
// result에 더해지므로 O(1)의 공간을 사용한다.
int mainSum(int N){
int result = 0;
for(int i=0; i<N; i++)
result += sum(i, i+1);
return result;
}
int sum(int a, int b){
return a + b;
}
빅오 표기법 (Big-O Notation), 시간 복잡도, 공간 복잡도[Juhun님]