어떤 함수를 실행한다고 가정해보자. 함수의 성능을 알고싶다. 함수의 성능을 측정하려면 어떻게 해야할까?
아쉽게도 컴퓨터 메모리, CPU 등 각각의 컴퓨터가 처한 상황에 따라 성능이 달라지기 때문에 정확한 성능을 측정하기란 어렵다.
그래서 성능을 조금 간단하게 표현해보기 위해서 실행시간을 다음과 같이 정의해보자.
실행 시간(running time)이란?
"함수/알고리즘 수행에 필요한 스텝(step) 수"
또 각 라인을 수행하기 위해 필요한 스텝 수는 상수(constant)라고 가정해보자.
예제로 살펴보자.
function multiply(inputs:number[], multiplier:number) {
const nums = Array.from({ length: inputs.length }); // c1
for(let i = 0; i< inputs.length; i++) { // c2
nums[i] = inputs[i] * multiplier; // c3
}
return nums; // c4
}
| cost | times |
|---|---|
| c1 | 1 |
| c2 | N+1 |
| c3 | N |
| c4 | 1 |
각 라인의 cost를 매기고 각 라인이 몇번씩 실행되는지를 표로 나타내보았다.
이를 수식으로 나타내면 다음과 같다.
여러가지 변수 때문에 위 수식보다 더 정확한 계산은 어렵다.
=> θ(N) - 점근적 표기법
위와 같이 N -> ∞ 일 때를 가정하여 분석하는 방식을 점근적 분석(Asymptotic analysis) 라고 한다.
임의의 함수가 N -> ∞ 일 때 어떤 함수 형태에 근접해지는지 분석하는 방법이다.
시간복잡도란?
함수의 실행 시간을 표현하는 것이다.
주로 점근적 분석을 통해 실행 시간을 단순하게 표현하고 점근적 표기법으로 표현한다.
function exists(inputs:number[], target:number) {
for (let i = 0; i < input.length; i++) {
if(inputs[i] === target) {
return true;
}
}
return false;
}
찾는 수가 앞에 있다면 실행시간이 짧고, 찾는 수가 뒤에 있다면 실행시간이 길다. 이 때는 케이스를 나누어서 생각해보자.
| case | when | times |
|---|---|---|
| best | 0번째에 존재 | 1 |
| worst | 마지막에 존재 or 존재하지 않음 | N |
위 함수의 시간복잡도를 점근적 표기법으로 정리해보면 다음과 같이 표현할 수 있다.
일반적으로 upper bound를 기준으로 한 빅오 노테이션 O(N)으로 많이 표현한다.

이진탐색을 하는 함수가 있다고 가정해보고 시간복잡도를 구해보자.
Worst Case : 찾는게 없을 때 (105를 찾을 때)

매번 실행할 때 마다 1/2 씩 사이즈가 줄어든다. 몇 번만에 사이즈가 1이 되는가?
N * (1/2)k = 1
=> k = log2N
= θ(logN)
Best Case : 한번에 찾았을 때
= θ(1)

