개요
Chapter 3는 알고리즘의 running time을 정확한 식이 아니라 입력 크기 n이 커질 때의 성장률(growth rate)로 다루는 방법을 정리한다. Chapter 2에서 insertion sort의 worst-case 와 merge sort의 을 비교했다면, 이 장은 그 표기법을 엄밀하게 정의하고, 알고리즘 분석에서 자주 등장하는 standard functions의 성질을 정리한다.
핵심 관점은 asymptotic efficiency다. 입력 크기가 충분히 커지면 exact running time의 multiplicative constants와 lower-order terms보다 input size 자체가 성능 차이를 지배한다. 따라서 asymptotically more efficient algorithm은 매우 작은 입력을 제외한 대부분의 입력에서 더 좋은 선택이 된다.
핵심 개념
| 용어 | 핵심 의미 | 검색 키워드 |
|---|---|---|
| asymptotic efficiency | n이 무한히 커질 때 running time이 어떻게 증가하는지 보는 효율성 | asymptotic efficiency |
| asymptotic notation | 함수의 성장률을 constant factor와 충분히 큰 n 기준으로 비교하는 표기 | asymptotic notation |
| Θ-notation | 위아래 constant factor로 동시에 묶는 asymptotically tight bound | |
| O-notation | 위쪽 constant factor bound, asymptotic upper bound | |
| Ω-notation | 아래쪽 constant factor bound, asymptotic lower bound | |
| o-notation | 어떤 constant factor로도 위에서 엄격히 작아지는 asymptotic upper bound | o(g(n)), strictly smaller |
| ω-notation | 어떤 constant factor로도 아래에서 엄격히 커지는 asymptotic lower bound | |
| asymptotically nonnegative | 충분히 큰 n에서 0 이상인 함수 | asymptotically nonnegative |
세부 정리
3.1 Asymptotic notation
왜 exact running time을 버리는가
정확한 running time을 구할 수 있는 경우도 있지만, 보통 그 정밀도는 계산 노력에 비해 큰 이득을 주지 않는다. Chapter 2의 insertion sort 분석처럼 같은 식을 얻어도, 충분히 큰 입력에서는 lower-order terms와 constant factor보다 최고차 성장률이 더 중요하다.
이때 우리가 보는 것은 algorithm의 asymptotic efficiency다. 이는 input size가 bound 없이 커질 때 running time이 어떤 비율로 증가하는지에 관한 성질이다. 예를 들어 merge sort는 insertion sort보다 충분히 큰 입력에서 asymptotically more efficient하다.
Asymptotic notation은 function에 적용된다
CLRS는 asymptotic notation을 알고리즘의 running time을 표현하는 데 주로 사용하지만, 엄밀히는 notation이 function에 적용된다고 설명한다. INSERTION-SORT의 worst-case running time을 로 나타낸 뒤 라고 쓰는 것은, 그 running-time function이 에 속한다는 뜻이다.
따라서 asymptotic notation은 running time뿐 아니라 space usage나 알고리즘과 무관한 수학적 function에도 적용될 수 있다. 또한 running time에 적용할 때도 “worst-case running time”인지, “모든 input에 대한 blanket statement”인지 구분해야 한다.
기본 정의의 domain은 natural numbers 다. 이는 input size가 보통 정수이기 때문이다. 다만 실제 분석에서는 real numbers로 확장하거나 natural numbers의 subset에 제한하는 식의 abuse를 할 때가 있다. CLRS의 태도는 “abuse는 하되 misuse는 하지 말자”에 가깝다. 즉 표기의 정확한 뜻을 알고 편의상 확장해야 한다.
Θ-notation: asymptotically tight bound
은 과 같은 성장률을 constant factor 범위 안에서 갖는 함수들의 집합이다.
즉 충분히 큰 부터 이 과 사이에 끼어 있으면 라고 쓴다. 엄밀히는 가 맞지만, CLRS는 관례적으로 라고 쓴다. 여기서 은 의 asymptotically tight bound다.
Figure 3.1은 Θ, O, Ω의 직관을 한 그림에 모아 보여준다. Θ는 위와 아래에서 동시에 묶는 tight bound이고, O는 위쪽 bound, Ω는 아래쪽 bound다.
Figure 3.1 · PDF p. 66 · Θ, O, Ω notation의 constant-factor bound 직관
정의에서 중요한 조건은 이후만 본다는 점이다. 에서 함수들이 어떻게 움직이는지는 asymptotic bound에 영향을 주지 않는다. 또한 , , 는 하나로 고정된 “정답”이 아니라 존재하기만 하면 된다. 더 큰 나 다른 constants도 가능하다.
Asymptotically nonnegative 조건
의 정의는 형태를 갖기 때문에, 은 충분히 큰 에서 nonnegative여야 한다. 이를 asymptotically nonnegative라고 한다. 충분히 큰 에서 positive이면 asymptotically positive function이다.
결과적으로 도 asymptotically nonnegative여야 이 비어 있지 않다. CLRS는 이후 이 장의 모든 asymptotic notation 안에 들어가는 함수가 asymptotically nonnegative라고 가정한다.
Lower-order terms와 leading coefficient를 무시해도 되는 이유
Chapter 2의 비공식 규칙, 즉 lower-order terms를 버리고 leading coefficient를 무시한다는 직관은 Θ의 formal definition으로 정당화된다. 예를 들어
임을 보이려면 positive constants , , 가 존재해
가 모든 에서 성립함을 보이면 된다. 원문은 , , 같은 선택이 가능하다고 보인다. 중요한 것은 특정 constants가 유일하다는 점이 아니라, 어떤 적절한 constants가 존재한다는 점이다.
반대로 은 가 아니다. 만약 가 충분히 큰 모든 에서 성립해야 한다면, 나누어서 이 되어야 한다. 하지만 는 constant이므로 임의로 큰 에 대해 성립할 수 없다.
일반적으로 최고차항 계수가 양수인 polynomial
은 다. Constant function은 degree 0 polynomial이므로 , 즉 흔히 로 쓴다.
O-notation: asymptotic upper bound
-notation이 함수의 위와 아래를 동시에 묶는다면, -notation은 위쪽 bound만 준다. 은 충분히 큰 에서 이 의 어떤 constant multiple 이하로 제한되는 함수들의 집합이다.
이면 반드시 이다. 즉 이다. 하지만 반대는 일반적으로 성립하지 않는다. 예를 들어 는 맞지만 는 아니다.
CLRS는 O-notation을 asymptotically tight bound로 쓰지 않는다. 일부 문헌에서는 O를 느슨하게 “대략 그 정도”로 쓰지만, 이 책에서 은 오직 의 constant multiple이 의 asymptotic upper bound라는 주장일 뿐이다. Tightness를 말하려면 를 써야 한다.
O-notation은 알고리즘 구조만 보고 빠르게 upper bound를 잡을 때 유용하다. 예를 들어 insertion sort의 double nested loop 구조만 봐도 inner loop의 각 iteration cost는 이고, i, j 조합은 최대 개이므로 worst-case running time이 임을 바로 알 수 있다.
Running time을 O로 말할 때의 의미
“Insertion sort의 running time은 이다”라는 문장은 엄밀히는 약간의 abuse다. 같은 size n의 input이라도 실제 running time은 입력 상태에 따라 달라지기 때문이다. 이 문장의 정확한 뜻은 다음과 같다.
모든 size
n의 input에 대해 실제 running time을 위에서 제한하는 어떤 function 가 존재한다.
동치로 말하면 worst-case running time이 이라는 뜻이다. 따라서 worst-case에 대한 O bound는 모든 input에 대한 blanket upper bound를 준다.
반면 “insertion sort의 worst-case running time은 ”라는 말은 “모든 input에서 가 걸린다”는 뜻이 아니다. 이미 정렬된 input에서는 insertion sort가 에 실행된다.
Ω-notation: asymptotic lower bound
Ω-notation은 O-notation의 반대 방향이다. 은 충분히 큰 n에서 이 의 어떤 positive constant multiple 이상인 함수들의 집합이다.
는 lower bound다. 알고리즘의 running time에 modifier 없이 “이다”라고 말하면, 어떤 size n input을 골라도 running time이 충분히 큰 n에서 의 constant multiple 이상이라는 뜻이다. 동치로 best-case running time에 대한 lower bound다.
Insertion sort의 running time은 이면서 이다. 모든 input에서 적어도 linear 정도는 필요하지만, 모든 input에서 quadratic이라고 말할 수는 없다. 다만 worst-case running time은 라고 말할 수 있다. worst-case를 만드는 input, 즉 reverse sorted input이 존재하기 때문이다.
Theorem 3.1: Θ는 O와 Ω의 교집합
Theorem 3.1은 세 표기의 관계를 명확히 한다.
즉 asymptotically tight bound를 보이려면 upper bound와 lower bound를 함께 보이면 된다. 실제 증명에서는 를 먼저 보인 뒤 O, 를 얻기보다, O와 를 각각 증명한 뒤 Theorem 3.1로 를 결론내리는 경우가 많다.
Asymptotic notation in equations and inequalities
CLRS는 asymptotic notation을 equation 안에서도 사용한다. 이때 표기는 함수 집합을 나타내기도 하고, 이름 붙이지 않은 anonymous function을 나타내기도 한다.
처럼 asymptotic notation이 오른쪽에 단독으로 있으면, equal sign은 set membership을 뜻한다.
반면 더 큰 식 안에 나타나면, asymptotic notation은 이름 붙이지 않은 어떤 함수를 뜻한다.
이 식은 3n + 1을 어떤 로 보아 이라고 쓴 것이다. 이 방식은 recurrence에서 lower-order detail을 숨기는 데 유용하다. 예를 들어 merge sort recurrence
에서 은 divide와 combine에 드는 linear amount of work를 나타내는 anonymous function이다.
Asymptotic notation이 왼쪽에 나타나면 규칙이 조금 다르다.
이 문장은 왼쪽의 anonymous function을 어떻게 골라도, 오른쪽의 anonymous function을 적절히 골라 등식이 성립하게 할 수 있다는 뜻이다. 즉 오른쪽이 왼쪽보다 더 coarse한 수준의 detail을 제공한다.
따라서 다음과 같은 chaining도 가능하다.
직관적으로는 lower-order term을 먼저 로 뭉개고, 다시 전체를 로 뭉갠 것이다.
o-notation: non-tight upper bound
upper bound는 tight할 수도 있고 아닐 수도 있다. 는 tight하지만, 는 tight하지 않다. 이런 “엄격히 더 작은 성장률”을 나타내기 위해 -notation을 쓴다.
에서는 어떤 constant 하나만 찾으면 되지만, 에서는 모든 positive constant 에 대해 결국 이 되어야 한다. 즉 이 에 비해 asymptotically insignificant해진다.
Limit이 존재한다면 은 다음과 같은 직관과 대응한다.
ω-notation: non-tight lower bound
ω-notation은 Ω-notation에 대한 strict version이다. 이 보다 asymptotically larger하다는 뜻이다.
예를 들어 이지만, 이다. Limit이 존재하면 다음 직관과 대응한다.
Comparing functions
Asymptotic comparisons는 real number comparison과 비슷한 성질을 많이 가진다. 아래 성질들은 , , 이 asymptotically positive라고 가정할 때 사용한다.
| 성질 | 적용되는 표기 | 의미 |
|---|---|---|
| transitivity | , O, , o, | f가 g에 대해, g가 h에 대해 같은 관계면 f와 h도 그 관계다 |
| reflexivity | , O, | 은 자기 자신에 대해 tight/upper/lower bound다 |
| symmetry | iff | |
| transpose symmetry | 와 , 와 | iff , iff |
실수 비교와의 비유는 다음과 같다.
| Asymptotic comparison | Real-number analogy |
|---|---|
하지만 trichotomy는 함수 비교에 그대로 적용되지 않는다. 실수 , 는 반드시 , , 중 하나지만, 함수는 asymptotically incomparable할 수 있다. 원문 예시는 과 이다. 때문에 exponent가 0과 2 사이를 oscillate하므로, 어느 한쪽이 항상 asymptotic upper/lower bound라고 말하기 어렵다.
3.2 Standard notations and common functions
Monotonicity
함수의 단조성(monotonicity)은 알고리즘 분석에서 recurrence, summation bound, search space 감소를 다룰 때 자주 쓰인다.
| 용어 | 정의 |
|---|---|
| monotonically increasing | 이면 |
| monotonically decreasing | 이면 |
| strictly increasing | 이면 |
| strictly decreasing | 이면 |
예를 들어 는 이면 monotonically increasing이고, 이면 monotonically decreasing이다. Logarithm 은 base 이 고정되어 있으면 에서 strictly increasing이다.
Floors and ceilings
Floor와 ceiling은 array index, divide-and-conquer split, recurrence에서 정수 크기를 다룰 때 필요하다.
| 표기 | 의미 |
|---|---|
| 이하의 가장 큰 integer, floor of | |
| 이상의 가장 작은 integer, ceiling of |
기본 부등식은 다음과 같다.
정수 에 대해서는
이므로 merge sort처럼 array를 반으로 나눌 때 두 subproblem size가 정확히 합쳐져 원래 크기가 된다. Floor function과 ceiling function은 모두 monotonically increasing이다.
CLRS는 nested floor/ceiling을 단순화하는 식도 제공한다. 알고리즘 분석에서는 정확한 정수 반올림보다 “상수 차이 안에서 같은 성장률”이 중요한 경우가 많지만, recurrence를 엄밀히 다룰 때 , 같은 성질이 유용하다.
Modular arithmetic
Modular arithmetic은 hashing, number-theoretic algorithms, cryptography에서 기본이 된다. 정수 와 positive integer 에 대해
이다. 두 정수 , 의 remainder가 같으면
이라고 쓰고, is equivalent to , modulo 이라고 읽는다. 동치 조건은 이 를 나눈다는 것이다. 같지 않으면 이라고 표현한다.
Polynomials
Degree 의 polynomial은 다음 형태의 함수다.
는 coefficients이고, 는 leading coefficient다. Polynomial이 asymptotically positive인 것은 일 때와 정확히 대응한다. 이 경우
이다. 즉 알고리즘 분석에서 polynomial의 성장률은 최고차항의 degree가 결정한다.
함수 이 어떤 constant 에 대해 이면 polynomially bounded라고 한다. 이 표현은 “다항식 정도로 제한되는 성장”을 말할 때 자주 쓰이며, exponential이나 factorial과 대비된다.
Exponentials
Exponential functions는 polynomial보다 훨씬 빠르게 성장한다. 기본 항등식은 다음과 같다.
이면 은 에 대해 monotonically increasing이다. 편의상 로 가정할 때도 있다.
Polynomial과 exponential의 성장률 관계는 매우 중요하다. 모든 real constants , 에 대해
이다. 즉 base가 1보다 큰 exponential function은 어떤 polynomial function보다도 asymptotically faster하게 성장한다.
자연상수 는 natural logarithm의 base이며, 다음 급수로 정의된다.
자주 쓰는 부등식과 근사는 다음과 같다.
여기서 의 asymptotic notation은 가 아니라 에서의 limiting behavior를 설명한다. 이는 asymptotic notation이 본질적으로 “어떤 변수가 극한으로 갈 때의 함수 행동”을 나타낸다는 점을 보여준다.
Logarithms
CLRS의 logarithm notation은 다음과 같다.
| 표기 | 의미 |
|---|---|
| , binary logarithm | |
| , natural logarithm | |
| , exponentiation | |
| , composition |
중요한 convention은 logarithm이 다음 term에만 적용된다는 것이다. 따라서 는 이고 가 아니다.
Logarithm 항등식 중 특히 자주 쓰는 것은 base change다.
Base가 constant이면 logarithm base를 바꾸는 것은 constant factor만 바꾼다. 그래서 -notation이나 -notation처럼 constant factor를 무시하는 맥락에서는 보통 을 대표 표기로 쓴다. Computer science에서 base 2가 자연스러운 이유는 많은 algorithms와 data structures가 problem을 two parts로 나누기 때문이다.
그 밖의 기본 항등식은 다음과 같다.
에는 에서의 series expansion이 있고, 에 대해 다음 부등식이 사용된다.
함수 이 어떤 constant 에 대해 이면 polylogarithmically bounded라고 한다. Polynomial과 polylogarithm의 성장률 관계는 다음과 같다.
즉 어떤 positive polynomial function도 어떤 polylogarithmic function보다 asymptotically faster하게 성장한다.
Factorials
Factorial function은 permutation 수, brute-force search space, combinatorial counting에서 자주 등장한다. 정수 에 대해
이며, 따라서 이다. 약한 upper bound로는 각 항이 최대 이므로
이 성립한다.
더 정밀한 근사는 Stirling’s approximation이다.
Stirling’s approximation으로 다음 성장률 관계를 얻는다.
즉 factorial은 같은 fixed-base exponential보다 크지만, 보다는 작다. 또 자체는 매우 빠르게 커지지만 그 logarithm은 order다. 이 성질은 comparison sorting lower bound나 permutation counting에서 자주 연결된다.
Functional iteration
Functional iteration은 같은 함수를 반복 적용하는 표기다. 은 초기값 에 함수 를 번 적용한 결과다.
예를 들어 이면
이다. 이 표기는 iterated logarithm처럼 “몇 번 반복 적용해야 특정 threshold 아래로 내려가는가”를 표현할 때 중요하다.
Iterated logarithm:
Iterated logarithm , 즉 log star of 은 를 몇 번 반복 적용해야 값이 1 이하가 되는지를 나타낸다.
여기서 은 logarithm function을 번 연속 적용한 것이고, 와 다르다. 이 둘을 혼동하면 안 된다.
대표 값은 다음과 같다.
| n | |
|---|---|
은 극도로 천천히 증가한다. 원문은 observable universe의 atom 수가 약 이고 이것이 보다 훨씬 작으므로, 실제로 인 input size를 거의 만나지 않는다고 설명한다.
Fibonacci numbers
Fibonacci numbers는 다음 recurrence로 정의된다.
따라서 sequence는 다음과 같이 시작한다.
Fibonacci numbers는 golden ratio 와 그 conjugate 에 연결된다. 둘은 equation
의 두 root다.
Fibonacci number의 closed form은 다음과 같다.
이므로 의 절댓값은 항상 보다 작다. 따라서 는 를 nearest integer로 반올림한 값이다.
결론적으로 Fibonacci numbers grow exponentially. 이 성질은 naive recursive Fibonacci algorithm이 왜 지수적으로 느려지는지, 그리고 dynamic programming이나 memoization이 왜 효과적인지 설명하는 배경이 된다.
Exercises와 Problems가 요구하는 핵심 능력
Chapter 3의 exercises는 정의를 외우는 것보다, asymptotic notation을 정확히 조작하는 능력을 요구한다.
| 항목 | 핵심 능력 |
|---|---|
| asymptotically nonnegative functions에서 sum과 max의 관계를 constants로 증명 | |
| 상수 shift가 polynomial growth를 바꾸지 않음을 증명 | |
| vs , vs | constant factor와 exponential factor 차이 구분 |
| two-parameter notation | , 이 독립적으로 커질 때의 asymptotic bound 확장 |
| relative asymptotic growths | , , , , 같은 함수군 순서 비교 |
| asymptotic notation properties | , , , , 의 참/거짓 명제를 반례나 정의로 판정 |
soft-oh Õ | logarithmic factors를 무시하는 변형 notation 이해 |
| iterated functions | 을 일반화해 어떤 함수 반복이 threshold까지 몇 번 필요한지 분석 |
특히 Problem 3-3의 ordering by asymptotic growth rates는 이 장의 종합 문제다. 함수들을 growth rate 순서로 정렬하고 equivalence class로 묶는 훈련을 시킨다. 이 문제는 나중에 알고리즘 후보들의 running time을 비교할 때 “어느 항이 진짜 지배적인가”를 빠르게 판단하는 감각과 연결된다.
Chapter notes는 asymptotic notation의 역사적 배경도 짧게 언급한다. -notation은 Bachmann의 number theory text에서, -notation은 Landau의 prime distribution 논의에서 유래했고, 와 는 를 upper/lower/tight bound에 모두 쓰는 관행을 바로잡기 위해 Knuth가 강조한 표기다. 중요한 실전 포인트는 문헌마다 표기 정의가 약간 다를 수 있으므로, 어떤 의미의 , , 를 쓰는지 항상 문맥을 확인해야 한다는 점이다.
비교
Chapter 3의 growth hierarchy를 알고리즘 분석 관점에서 정리하면 다음과 같다. 아래로 갈수록 더 빠르게 증가하는 함수군이다.
| 성장률 계층 | 대표 예 | 핵심 관계 |
|---|---|---|
| constant | input size와 무관 | |
| iterated logarithmic | 거의 모든 현실적 input에서 작은 상수처럼 보일 정도로 느림 | |
| logarithmic | , | binary search, balanced tree height |
| polylogarithmic | 모든 positive polynomial보다 느림 | |
| polynomial | , , , | for |
| polynomial-log | , | sorting lower bound, merge sort |
| exponential | , | 모든 polynomial보다 빠름 |
| factorial | permutation brute force, and | |
| super-exponential examples | , | 조합 폭발을 설명할 때 등장 |
자주 쓰는 비교식만 따로 모으면 다음과 같다.
연결 관계
Chapter 3는 이후 CLRS 전반의 분석 언어다. Chapter 4의 recurrences와 master theorem은 , , 로 결과를 표현한다. Sorting lower bound, dynamic programming table size, graph algorithm complexity, amortized analysis 모두 이 장의 notation과 function comparison을 계속 사용한다.
Chapter 2에서 을 비공식적으로 다뤘다면, Chapter 3는 그 이 anonymous function이고, exact lower-order terms를 숨기는 표기라는 점을 명확히 한다. Chapter 4 이후부터는 이 관례가 recurrence에 자연스럽게 들어간다.
또한 standard functions는 알고리즘 패턴과 연결된다. 은 halving search나 balanced tree height, 은 divide-and-conquer sorting, 은 subset enumeration, 은 permutation enumeration, 은 극히 느리게 증가하는 반복 구조, Fibonacci growth는 naive recursion의 exponential blow-up과 연결된다.
오해하기 쉬운 내용
- 은 tight bound가 아니다. 는 참이지만 는 거짓이다.
- “running time is ”는 보통 worst-case upper bound 또는 모든 input을 덮는 upper-bound function이 있다는 뜻이다.
- “at least ” 같은 표현은 의미가 흐리다. 아래쪽 bound를 말하려면 를 써야 한다.
- 는 와 가 동시에 성립할 때다.
- 는 단순히 보다 작은 느낌이 아니라, 모든 constant factor보다 eventually 작아지는 strict upper bound다.
- Asymptotic notation이 equation 안에 들어가면 anonymous function을 뜻할 수 있다. 는 일반 등호처럼 좌우 집합이 같다는 뜻이 아니다.
- 모든 함수 쌍이 asymptotically comparable한 것은 아니다. 과 처럼 oscillation이 있으면 도 도 아닐 수 있다.
- 은 이고, 은 logarithm을 k번 반복 적용한 것이다.
- Logarithm base가 constant이면 asymptotic notation 안에서는 constant factor 차이만 만든다. 그래도 정확한 수식 변형에서는 base change를 명시해야 한다.
- 은 “log를 한 번 취한 값”이 아니라 “log를 몇 번 반복해야 1 이하가 되는가”를 나타내는 함수다.
면접 질문
- , , 의 formal definition을 constants , , , 를 사용해 설명하라.
- iff and 인 이유를 설명하라.
- 왜 는 참이지만 는 거짓인가?
- Insertion sort의 worst-case running time이 인 것과 running time이 모든 input에서 라는 말의 차이를 설명하라.
o(g(n))와 , 와 의 차이를 limit 관점에서 설명하라.- 같은 식을 어떻게 해석해야 하는가?
- 과 의 차이를 예시와 함께 설명하라.
- 왜 모든 positive polynomial은 polylogarithmic function보다 asymptotically faster하게 성장하는가?
- 왜 base가 1보다 큰 exponential function은 어떤 polynomial보다 빠르게 성장하는가?
- Stirling’s approximation을 이용해 이 되는 직관을 설명하라.
- 이 왜 현실적인 input size에서 거의 상수처럼 보이는지 설명하라.
- Fibonacci numbers가 exponentially grow한다는 말이 naive recursive Fibonacci algorithm 분석과 어떻게 연결되는가?