시간복잡도

시간복잡도

백준같은 곳에서 알고리즘을 공부하다 보면 필연적으로 시간복잡도라는 개념을 한 번쯤은 보게 된다. 단순히 어떤 알고리즘의 시간복잡도가 \(\mathcal{O}(n^2)\)라는 것을 입력의 크기가 \(n\)일 때 최악의 경우에 실행 시간이 \(n^2\)에 비례한다는 것만 알아도 알고리즘 문제를 푸는 것에는 큰 영향이 없지만, 이 글에서는 시간복잡도의 수학적 정의에 대해서 알아보고자 한다.

시간복잡도를 나타내는 방법은 Big \(\mathcal{O}\), Big \(\theta\), Big \(\Omega\)로 크게 3가지가 있다.

Big $\mathcal{O}$

\[\text{어떤 양의 상수 } M, c\text{과 } M \text{이상의 모든 } x\text{에 대해 } \vert f(x)\vert \le c\vert g(x)\vert\text{일 때 } f(x)\in \mathcal{O}(g(x))\]

보통 위의 정의를 만족할 때 이해하기 쉽도록 \(f(x)=\mathcal{O}(g(x))\)라고 표기하는 경우도 있지만, 여기서는 좀 더 엄밀하게 하기 위해 \(f(x) \in \mathcal{O}(g(x))\)로 표기하도록 하겠다.

점근적 분석과 Big O 표기법. 점근적 분석은 다양한 알고리즘에서 성능을 비교할 때 사용되는… | by 이희랑 | Medium

위 그림에서 보면, \(n\)이 \(n_0\)보다 큰 모든 경우에 \(\vert f(n)\vert \le c\vert g(n)\vert\)이므로 \(f(n) \in \mathcal{O}(g(n))\) 이다.

예를 들어 \(f(x) = x^2\)라고 하자.

만약 \(g(x) = x^3\)이라면 \(c\)가 어떤 양수가 되더라도 충분히 큰 \(M\)가 있어 모든 \(M\)보다 큰 \(x\)에 대해 \(f(x) \le cg(x)\)이므로 \(f(x) \in \mathcal{O}(g(x))\)이다.

만약 \(g(x) = x^2 - 3x\)이라면 \(c\)가 모든 양수는 아니더라도 충분히 큰 \(c, M\)이 있어 \(M\)보다 큰 모든 \(x\)에 대해 \(f(x) \le cg(x)\)이므로 \(f(x) \in \mathcal{O}(g(x))\)이다.

하지만 \(g(x) = x\)이라면 \(c\)가 어떤 수가 되더라도 충분히 큰 \(x\)에 대해 \(f(x) > cg(x)\)이므로 \(f(x) \notin \mathcal{O}(g(x))\)이다.

Big $ \Omega $

\[\text{어떤 양의 상수 } M, c\text{과 } M \text{이상의 모든 } x\text{에 대해 } \vert f(x)\vert \ge cg(x)\text{일 때 } f(x)\in \Omega(g(x))\]

즉, \(Big \mathcal{O}\)와 반대라고 생각하면 편하다.

이번에도 예를 들어 \(f(x) = x^2\)라고 하자.

만약 \(g(x) = x^3\)이라면 \(c\)가 어떤 양수가 되더라도 충분히 큰 \(x\)에 대해 \(\vert f(x)\vert < c\vert g(x)\vert\)이므로 \(f(x) \notin \Omega(g(x))\)이다.

만약 \(g(x) = x^2 - 3x\)이라면 \(c\)가 모든 양수는 아니더라도 충분히 작은 \(c\)와 충분히 큰 \(M\)가 있어 \(M\)보다 큰 모든 \(x\)에 대해 \(\vert f(x)\vert \ge c\vert g(x)\vert\)이므로 \(f(x) \in \Omega(g(x))\)이다.

그리고 \(g(x) = x\)이라면 충분히 큰 \(M\)이 있고 \(c\)가 어떤 양수가 되더라도 충분히 큰 \(x\)에 대해 \(\vert f(x)\vert \ge c\vert g(x)\vert\)이므로 \(f(x) \in \Omega(g(x))\)이다.

Big $\theta$

\[f(x) \in \mathcal{O}(g(x)) \text{이고 } f(x) \in \Omega(g(x)) \text{일 때 } f(x) \in \theta(g(x))\]

사실 Big \(\theta\)는 이게 끝이다.


성질

Big \(\mathcal{O}\), Big \(\Omega\), Big \(\theta\) 표기법에는 여러 성질들이 있다.

1. 반사성

\[f(x) \in \mathcal{O}(f(x)), f(x) \in \Omega(f(x)), f(x) \in \theta(f(x))\]

2. 전이성

\[f(x) \in \mathcal{O}(g(x)), g(x) \in \mathcal{O}(h(x)) \text{이면 } f(x) \in \mathcal{O}(h(x))\]

\[f(x) \in \Omega(g(x)), g(x) \in \Omega(h(x)) \text{이면 } f(x) \in \Omega(h(x))\]

\[f(x) \in \theta(g(x)), g(x) \in \theta(h(x)) \text{이면 } f(x) \in \theta(h(x))\]

3. 대칭성

\[f(x) \in \theta(g(x)) \Leftrightarrow g(x) \in \theta(f(x))\]

4. 전치 대칭성

\[f(x) \in \mathcal{O}(g(x)) \Leftrightarrow g(x) \in \Omega(f(x))\]

5. 덧셈 규칙

위에서 추측할 수 있듯이, \(\mathcal{O}(f(x)), \Omega(f(x)), \theta(f(x))\)는 전부 다 집합이다.

\[\mathcal{O}(f(x)) + \mathcal{O}(g(x)) = \mathcal{O}(f(x) + g(x))\]

\[\Omega(f(x)) + \Omega(g(x)) = \Omega(f(x) + g(x))\]

\[\theta(f(x)) + \theta(g(x)) = \theta(f(x) + g(x))\]

예를 들어 \(\mathcal{O}(x^2) + \mathcal{O}(x) = \mathcal{O}(x^2+x) \text{이고, } \mathcal{O}(x^2+x) = \mathcal{O}(x^2)\)이므로 \(x\)가 충분히 큰 수라고 생각했을 때

\[\mathcal{O}(f(x)) + \mathcal{O}(g(x)) = \mathcal{O}(max(f(x), g(x)))\]

으로 써도 무방하다. 마찬가지로

\[\Omega(f(x)) + \Omega(g(x)) = \Omega(min(f(x), g(x)))\]

도 성립한다.

6. 곱셈 규칙

\[\mathcal{O}(f(x)) \cdot \mathcal{O}(g(x)) = \mathcal{O}(f(x) \cdot g(x))\]

\[\Omega(f(x)) \cdot \Omega(g(x)) = \Omega(f(x) \cdot g(x))\]

\[\theta(f(x)) \cdot \theta(g(x)) = \theta(f(x) \cdot g(x))\]

\(f(x) = x^2, g(x) = log(x)\)라 하자. \(x\)가 충분히 클 때 \(\mathcal{O}(f(x))\)에 속한 함수는 \(f(x)\)보다 작거나 같고, \(\mathcal{O}(g(x))\)에 속하는 함수는 \(g(x)\)보다 작거나 같다. 당연히 이 둘의 곱은 \(\mathcal{O}(f(x) \cdot g(x))\)보다 작거나 같다.

어떤 알고리즘이 좋을까?

잠시 정보과학의 영역으로 넘어와 보자. 알고리즘의 시간복잡도는 알고리즘의 효율성을 따질 때 중요한 지표 중 하나인데, 맨 처음에도 말했듯이 Big \(\mathcal{O}\) 표기법으로 나타낼 수 있다. \(0 < a < b\)인 \(a, b\)가 존재하고 \(x\)가 충분히 클 때, 알고리즘의 시간복잡도 별 걸리는 시간은 아래와 같다.

\[\mathcal{O}(1) < \mathcal{O}((log(x))^a) < \mathcal{O}((log(x))^b) < \mathcal{O}(x^a) < \mathcal{O}(x^b) < \mathcal{O}(a^x) < \mathcal{O}(b^x) < \mathcal{O}(x!)\]

위의 부등식들과 덧셈 규칙, 곱셈 규칙을 잘 결합하면 알고리즘이 얼마나 효율적인 것인지 알 수 있을 것이다.

결론

처음에는 수학적으로 엄밀하게 시간복잡도를 정의하고 그의 성질들도 엄밀하게 설명하려 했지만, 글을 써내려 갈수록 어쩔 수 없이 직관을 요하는 부분이 많았던 것도 사실이다. 이 점은 독자의 양해를 바란다. 이 글을 다 읽었다면 앞으로는 Big \(\mathcal{O}\) 표기법이 나와도 두려워 할 것 없다. 그러니 여러 알고리즘들을 배울 때 시간복잡도 표기가 나오면 위의 정의와 성질들을 곱씹으며 그것이 무엇을 의미하는지 확실히 이해하기를 바란다.