자동차중 뭐가 더 빠른지 확인하기 위해 km란 단위를 사용합니다. 단거리 육상 선수가 얼마나 빠른지 몇초만에 50m를 주파하는지 검사합니다. 알고리즘에서는 뭐가 더 좋은 알고리즘일까요? 만약 어떤게 더 좋은 알고리즘이라면 어떤 기준으로 정할까요?
이번 게시물에는 어떤 기준으로 정하는지 어떻게 그 기준을 구하는지 배워 보겠습니다.
예시 1
float sum(float list[], int n) {
float tempsum = 0;
int i = 0;
for (int i = 0; i < n; i++) {
tempsum += list[i];
}
return tempsum;
}
위 알고리즘에서
이것이 가변 공간인 이유는 call by reference로 언어마다 다르겠지만
입력 instance마다 공간의 크기가 달라지기 때문이다
SUM (s/e)X(frequency)
+변수의 선언은 step으로 계산 X
예시 2
void add(int a[][M_SIZE]) {
int i, j;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
c[i][j] = a[i][j] + b[i][j];
}
}
}
위 예시를 보고 시간복잡도를 구해보겠습니다.
선언은 step 수 포함이 안되기 때문에 매개인자 부분과 1번째줄은 step 수는 0이다.
그리고 for문의 조건식 부분은 m번 반복 된다고 생각할 수 있는데 마지막에 반복문을 빠져나올때 조건식 검사를 하기 때문에 m+1번반복하고 반복문 안에 실행문은 m번 반복한다.
그럼 아래 for문은 m(n+1)번 반복할 것이다.
마지막으로 안에 실행문은 mn번 반복한다.
따라서 시간 복잡도는 총합인 2mn + 2*m +1인 것을 볼 수 있다.
위에 공간 복잡도와 시간 복잡도를 사용해서 비교하면 정확할 순 있지만 다른 알고리즘과 비교하기 어렵습니다.
그래서 저희는 점근적으로 표기하여 어떤 알고리즘이 기껏해야 어느 정도 보다 크고 적어도 어느 정도 보다 작다로 표기하여 알고리즘의 효율성을 비교하기 쉽게 표기합니다.
일반적으로 알고리즘을 비교할때 상한 표현인 빅오를 사용합니다.
정의: 모든 n에 대해 f(n) ≤ Cg(n) (여기서 C ≥ 1)이 성립할 때, f(n)의 시간 복잡도를 O(g(n))로 표기한다.
이처럼 빅오 표현 예들을 볼 수 있는데 이정도 예제들을 풀어보고 다양한 예제들을 접해보면
굳이 시간 복잡도를 하나하나 구하지 않아도 빅오로 표현 할 수 있습니다.
정의: 함수 f(n)이 양의 상수 C와 함수 g(n)이 존재하여, 모든 n에 대해 f(n) ≥ Cg(n) (여기서 C > 0)이 성립할 때, f(n)의 시간 복잡도를 Ω(g(n))으로 표기합니다.
알고리즘의 최선의 경우 시간 복잡도를 나타냅니다. 하한 표기법은 빅오 표기법과 유사하지만, 알고리즘의 실행 시간이 아래로 제한될 때 사용됩니다.
함수 f(n)이 양의 상수 C1, C2와 함수 g(n)이 존재하여, 모든 n에 대해 C1g(n) ≤ f(n) ≤ C2g(n) (여기서 C1 > 0, C2 > 0)이 성립할 때, f(n)의 시간 복잡도를 Θ(g(n))으로 표기합니다.
즉, Theta(Θ) 표기법은 함수 f(n)이 g(n)의 상한과 하한으로 동시에 제한된다는 의미입니다. 이는 알고리즘의 실행 시간이 상한과 하한에 의해 제한되어 있다는 것을 나타냅니다.
Theta(Θ) 표기법을 사용하면 알고리즘의 성능을 보다 정확하게 평가하고, 최적의 알고리즘 선택이나 문제의 실행 시간을 예측하는 데 도움을 줄 수 있습니다.
마지막으로 big-O 표기법의 수행시간 효율성 비교 이미지 입니다
𝑂(1) < 𝑂(log n) < 𝑂(n) < 𝑂(n log n) < 𝑂(n²) < 𝑂(n³) < 𝑂(2ⁿ) < 𝑂(n!)
순으로 효율적입니다.