자료구조와 알고리즘 Chapter 03 ← 02 알고리즘04 속도 향상 →
제 3 장 · Big O Notation

확실해! Big O 표기법

"22단계 알고리즘"이라 부를 수는 없다. 단계 수는 데이터에 따라 변하기 때문이다. 컴퓨터 과학자들은 수학에서 빌려온 간결한 언어로 효율성을 분류한다 — O(1), O(log N), O(N).

O(1) O(log N) O(N) 로그 최악의 경우

§ 1 · 공통 언어단계 세기의 언어

Big O 표기법은 시간 단위 대신 알고리즘이 거치는 단계의 수에만 집중함으로써 일관성을 얻는다. 그리고 그 단계 수가 데이터가 증가할 때 어떻게 변하는지를 묻는다.

1장에서 배열 읽기는 크기와 관계없이 1단계였다. Big O로는 이렇게 쓴다.

상수 시간 — Constant Time
O(1)
O(1) — 데이터의 양과 관계없이 동일한 수의 단계를 수행하는 알고리즘. 1단계든 3단계든 100단계든, 일정하기만 하면 모두 O(1)이다.

선형 탐색은 최악의 경우 배열의 원소 수만큼 단계를 거친다.

선형 시간 — Linear Time
O(N)
O(N) — N개 데이터 원소에 대해 N단계를 수행한다. 데이터가 1개 늘면 단계도 1개 는다.
핵심 Big O는 특별히 명시하지 않는 한 최악의 경우를 의미한다. 선형 탐색은 최선의 경우 O(1)일 수 있지만(첫 셀에서 발견), 대부분의 자료는 이를 O(N)으로 설명한다. 비관적 접근이 최악에 대비하게 해주기 때문이다.

§ 2 · 수평선과 대각선상수 시간 vs 선형 시간

그래프 위에서 O(1)은 완벽한 수평선이다. 데이터가 늘어도 단계 수가 일정하기 때문이다. O(N)은 완벽한 대각선이다. 추가 데이터마다 1단계씩 늘기 때문이다.

흥미로운 점 — 항상 100단계를 수행하는 알고리즘도 일정하기만 하면 O(1)이다. 100단계 O(1)은 1단계 O(1)보다 덜 효율적이지만, 그래도 모든 O(N) 알고리즘보다 결국 빠르다. 어느 지점부터는 O(N)이 100을 넘어 무한대까지 더 많은 단계를 쓰기 때문이다.

모션 · 세 효율성 등급의 성장 곡선 단계 01 / 0
space 재생 · → 단계 · R 리셋

§ 3 · 지수의 역로그란 무엇인가

이진 탐색은 O(1)도 O(N)도 아니다. 둘 사이 어딘가에 있다. Big O는 이를 O(log N)으로 설명한다. 이해하려면 먼저 로그를 알아야 한다.

로그(logarithm)는 지수의 역이다. 2³ = 2 × 2 × 2 = 8이다. 그렇다면 log₂ 8은 그 반대를 묻는다 — "8을 얻으려면 2를 몇 번 곱해야 하나?" 답은 3이다.

로그 — 절반 나누기 관점
8 ÷ 2 ÷ 2 ÷ 2 = 1  ⟹  log₂ 8 = 3
log₂ N — N을 2로 계속 나눠 1에 도달할 때까지, 식에 등장하는 2의 개수. 즉 "1이 될 때까지 N을 절반으로 몇 번 나눌 수 있나?"
모션 · 64를 절반으로 계속 나누기 단계 01 / 0
space 재생 · → 단계 · R 리셋

§ 4 · 두 배에 1단계O(log N) 설명

O(log N)은 사실 O(log₂ N)의 줄임말이다. 편의상 작은 2를 생략한다. 의미는 이렇다 — O(log N)은 데이터를 반씩 계속 나눠 1개가 남을 때까지 걸리는 단계 수다. 8개 원소면 3단계, 16개면 4단계.

달리 말하면 데이터가 두 배가 될 때마다 1단계만 추가되는 알고리즘이다. 이진 탐색이 정확히 이렇게 한다.

O(N)과 O(log N)의 극적인 차이
N 원소O(N)O(log N)
883
64646
2562568
1024102410

효율성 순서대로(가장 빠른 것부터): O(1) → O(log N) → O(N). O(log N)은 살짝 위로 휜 곡선으로, O(1)보다는 덜 효율적이지만 O(N)보다는 훨씬 효율적이다.

§ 5 · 코드에 적용실제 코드 예제

리스트의 모든 항목을 출력하는 for 루프는, 원소가 4개면 4단계·10개면 10단계를 거친다. 원소 수만큼 단계를 거치니 O(N)이다.

소수 판별 알고리즘 — O(N) — Python
def is_prime(number):
    for i in range(2, number):
        if number % i == 0:
            return False
    return True

여기서 데이터는 배열이 아니라 함수에 전달된 숫자 그 자체다. is_prime(7)이면 루프가 약 7단계, is_prime(101)이면 약 101단계를 돈다. 단계 수가 전달된 숫자와 발맞춰 증가하므로 O(N)의 전형이다. 반면 print('Hello world!')는 항상 1단계 — O(1)이다.

직관 Big O는 알고리즘이 거치는 단계 수를 22나 400 같은 고정 숫자가 아니라, 데이터 크기에 대한 함수로 본다. 묻는 질문은 늘 하나다 — "데이터가 늘면 단계 수는 어떻게 변하는가?"

§ 6 · 정리이 장이 남긴 것

Big O 표기법을 손에 넣었으니, 이제 임의의 두 알고리즘을 일관된 체계로 비교할 수 있다. 다음 장부터는 이 도구로 실제 코드를 측정하고, 느린 알고리즘을 더 빠른 Big O 등급으로 끌어올리는 법을 배운다.