시간 복잡도는 해당 코드가 얼마나 많은 연산을 필요로 하는지를 나타내는 척도이다. Big O, Ω, Θ 등 다양하게 있지만 보통 프로그래밍에서 시간복잡도를 말할 때 Big O를 사용한다(각 차이는 뒤에서 설명).
Big O는 특정 범위의 시간을 기준으로 알고리즘의 시간복잡도를 분석하는 방법이다. 특정 범위의 시간이라고 말한 이유는 예로, 어떤 것을 한번 실행할 때 0.3초 걸리던 것이 1000번 실행할 때 0.33초로 느려진 경우를 보는 것이 아니라 30초로 느려지는 경우를 알고 싶어하는 것이다.
미세한 차이들을 접어두고 시간에 가장 중요한 변수가 되는 부분을 나타내는 방법으로 봐도 될 것이다.
2차 방정식을 예로 들어보자, 3x^2 + x + 1 x를 5로 정하면, 75 + 5 + 1 이다. 여기서 숫자를 대입했을 때 가장 큰 비중을 차지하는 숫자가 몇번째 숫자인가? 3x^2 인 75일 것이다. 그러나 이것도 보면, 3 * x^2 이다. 이 중에 가장 중요한 변수를 고르면, x^2 이다. (여기서 당연한 팁, 대입하는 x값이 클수록 그 차이는 더 분명할 것이다.) 그러므로 3x^2 + x + 1 의 Big O는 O(n^2) 가 되는 것이다.
for (var i = 0; i <= 5; i += 1) { console.log(i); }
O(1)
에 해당된다.
O(n)
만큼 복잡한 코드이다.
for (var i = 0; i <= n; i += 1) { console.log(i); }
2n
이나 3n
, 100n
등은 모두 O(n)
만큼 복잡하다고 본다. n 앞에 붙은 계수는 상수이므로, 변수인 n의 크기가 크면 클수록 무시할 수 있을 만큼 작다고 가정하기 때문이다. 따라서 아래의 코드도 O(n)
에 해당된다.
for (var i = 0; i <= n; i += 1) { console.log(i); } for (var i = 0; i <= n; i += 1) { console.log(i); } for (var i = 0; i <= n; i += 1) { console.log(i); }
for (var i = 0; i <= n; i += 1) { for (var j = 0; j <= n; j += 1) { console.log(i, j); } }
O(n^2)
에 해당된다. 만약 시간 복잡도가 2n^2 + 5n + 3
이라고 해도, O(n^2)
으로 간주한다. n^2
의 계수나, 그보다 낮은 차수의 항들은 n^2
에 비해 작은 수이기 때문이다.
O(log n)
의 시간 복잡도를 갖는 코드는 20의 복잡도를 갖는다.
log,[object Object],1048576 === 20
이기 때문이다. 굉장히 효율적인 케이스이다.
O(log n)
이 n번 반복되었을 때의 시간 복잡도이다. 병합 정렬(merge sort)의 시간 복잡도가 이에 해당된다. 이해를 위해서는 알고리즘에서 중요한 개념인 Divide and conquer를 살펴보면 된다.
function crossAdd(input) {
var answer = [];
for (var i = 0; i < input.length; i++) {
var goingUp = input[i];
var goingDown = input[input.length-1-i];
answer.push(goingUp + goingDown);
}
return answer;
}
function find(needle, haystack) {
for (var i = 0; i < haystack.length; i++) {
if (haystack[i] === needle) return true;
}
}
function makeTuples(input) {
var answer = [];
for (var i = 0; i < input.length; i++) {
for (var j = 0; j < input.length; j++) {
answer.push([input[i], input[j]]);
}
}
return answer;
}