English· Español· Deutsch· Nederlands· Français· 日本語· ქართული· 繁體中文· 简体中文· Português· Русский· العربية· हिन्दी· Italiano· 한국어· Polski· Svenska· Türkçe· Українська· Tiếng Việt· Bahasa Indonesia

un

게스트
1 / ?
수업 목록으로

수업에서 다룬 내용과 빠뜨린 내용 [BLOCK_TYPE SECTION/STEP]

해밍의 강의는 아날로그-디지털 변환, 오류 정정, 시뮬레이션, 통계, 수치 해석, n차원 기하학을 다루었다. 그는 계산적으로 사고했다 — 신호 처리, 코딩 이론, 디지털 필터링은 모두 계산적 추론을 필요로 한다. [BLOCK_TYPE SECTION/STEP]

그는 알고리즘 복잡도를 체계적으로 가르친 적이 없다. [BLOCK_TYPE SECTION/STEP]

알고리즘 복잡도 성장 곡선: O(1) 평평한 선, O(log N) 완만한 곡선, O(N) 대각선, O(N²) 포물선 [BLOCK_TYPE SECTION/STEP]

왜 그 공백이 존재했는가

해밍의 사고 모델은 하드웨어 병목 현상이 지배하던 시대에 형성되었다. 문제는 “칩당 트랜지스터 수는 몇 개인가?”였다. 알고리즘은 사용 가능한 하드웨어 위에서 실행되었다. N=100일 때 O(N²) 알고리즘은 10,000번의 연산이 필요하다. N=1,000일 때는 1,000,000번, N=10,000(의존성 그래프, 소셜 네트워크, 패키지 매니저에서 오늘날 흔한 규모)일 때는 100,000,000번이 필요하다. O(N)과 O(N²)의 차이는 해밍이 작업하던 규모에서는 보이지 않았지만, 그의 학생들이 살아갈 규모에서는 치명적이었다.

도널드 커누스는 1968년부터 《The Art of Computer Programming》을 출간하기 시작했다. 이는 해밍이 연구 활동이 절정에 달했던 해와 같다. Big O 표기법은 1970년대와 1980년대에 표준 알고리즘 용어로 자리 잡았다. 해밍의 강의는 1995년으로 거슬러 올라가지만, 그의 연산에 대한 사고 모델은 그보다 훨씬 이전에 형성되었다. 그는 이 장을 결코 업데이트하지 않았다.

해밍 자신의 기준으로 본 근본 원리

해밍이 정의한 근본 원리의 기준은 다음과 같다: (1) 오랫동안 지속되어 왔는가, (2) 나머지 분야가 이로부터 표준적인 방법으로 유도될 수 있는가.

Big O는 두 기준을 모두 충족한다. 성장률 분석은 커누스 이후로 계속 이어져 왔다. 이를 통해 알고리즘 선택, 데이터 구조 결정, 성능 예측을 유도할 수 있으며, 실용적인 컴퓨터 과학의 대부분은 “N이 커질 때 비용이 어떻게 증가하는가?”라는 질문에서 출발한다. 해밍은 자신의 분야에서 가장 오래 지속되는 근본 원리를 놓쳤다.

근본 원리로서의 Big O

해밍은 근본 원리가 특정 기술보다 오래 지속된다고 가르쳤다. 그는 미적분을 예로 들었다. 미적분은 한 번 발명된 후 수 세기 동안 물리학, 공학, 경제학, 생물학 등 여러 분야에 적용될 수 있다. 주변 도구는 생겼다 사라지지만, 근본 원리는 복리처럼 쌓인다.

해밍은 근본 원리가 특정 기술보다 오래 지속된다고 가르쳤다. 알고리즘 복잡도는 그의 기준에 따라 근본 원리로 볼 수 있는가? 그의 두 가지 기준을 적용해 보자: (1) 지속성, (2) 유도 가능성 — 이로부터 나머지 분야를 유도할 수 있는가? 구체적으로 자신의 입장을 논하라.

비용이 어떻게 증가하는가

Big O는 입력이 커짐에 따라 비용이 얼마나 증가하는지를 측정합니다. 상수 계수가 아니라, 증가율입니다. N=100에서 둘 다 ‘몇 밀리초’ 안에 끝나는 두 알고리즘이라도, 하나가 O(N)이고 다른 하나가 O(N²)라면 N=10,000에서는 10,000배 차이가 날 수 있습니다.

일반적인 복잡도 클래스

O(1) — 상수 시간. N과 관계없이 비용이 동일합니다. 예: 키로 해시 테이블 조회, 인덱스로 배열 접근, 스택 push/pop. N을 두 배로 늘려도 비용은 변하지 않습니다.

O(1) 성장 곡선: 수평 직선

O(log N) — 로그. 각 단계마다 남은 작업이 절반으로 줄어듭니다. 예: 정렬된 배열에서의 이진 탐색, 게임 엔진의 BVH 공간 쿼리, 균형 이진 트리 연산. N=1,000,000일 때: log₂(1,000,000) ≈ 20 단계.

O(log N) 성장 곡선: 급격한 상승 후 평탄화

O(N) — 선형. 입력 크기에 비례하여 비용이 증가합니다. 예: 리스트의 선형 탐색, 파일 읽기, 컬렉션 내 항목 개수 세기. N=10,000일 때: 10,000회 연산.

O(N) 성장 곡선: 직선 대각선

O(N log N) — 선형 로그. 거의 선형이지만 약간 더 나쁩니다. 예: 병합 정렬, 효율적인 최단 경로 알고리즘 (힙을 사용한 다익스트라). N=10,000일 때: 약 133,000회 연산.

O(N log N) 성장 곡선: 선형보다 약간 가파름

O(N²) — 제곱. 비용이 폭발적으로 증가합니다. 예: 동일한 리스트를 순회하는 루프 안에서 list.contains() 호출, 버블 정렬, 단순한 모든 쌍 비교. N=1,000일 때: 1,000,000회 연산. N=10,000일 때: 100,000,000회 연산.

O(N²) 성장 곡선: 포물선 폭발

O(2^N) — 지수. 의미 있는 규모에서는 사용할 수 없다. 예: 조합적 무차별 대입, 모든 부분집합 찾기. N=30일 때: 10억 회 이상의 연산.

O(2^N) 성장 곡선: 지수 폭발

보이게 만드는 규모

N=10 비교:
O(N):   10
O(N²):  100
비율:  10x

N=1,000 비교 횟수:
O(N):   1,000
O(N²):  1,000,000
비율:  1,000x

N=10,000 비교 횟수:
O(N):   10,000
O(N²):  100,000,000
ratio:  10,000x

N=10에서는 차이가 거의 드러나지 않습니다. N=10,000에서는 O(N²) 알고리즘이 10,000배 더 느리게 실행됩니다. 이것이 MOAD-0001이 수십 년 동안 눈에 띄지 않았던 이유입니다. 1993년에는 50개의 노드를 가진 그래프에서 실행되었지만, 2020년에는 동일한 코드가 50,000개의 노드를 가진 의존성 그래프에서 실행되었습니다.

세 가지 연산 분류하기

복잡도 클래스를 구체적인 연산에 적용하세요. 각 연산에 대한 핵심 질문은 N이 커질수록 연산 횟수가 얼마나 증가하는가입니다.

아래 각 연산에 대해 Big O 복잡도를 제시하고, 한 문장으로 이유를 설명하세요: (a) 페이지 번호로 사전에서 단어 찾기 (b) 사전의 모든 페이지를 검색하여 단어 찾기 (c) 가능한 모든 순서를 시도하여 섞인 카드 덱 정렬하기 각 연산에 대해 한 문장으로 설명을 작성하세요.

올바른 코드, 잘못된 성장 곡선

O(N²) 시간 복잡도로 실행되는 올바른 코드는 O(N) 코드와 동일한 결과를 생성한다. 테스트는 통과하고, 출력은 일치하며, 예외도 발생하지 않는다. 결함은 성장 곡선 속에 숨겨져 있다.

이 특성 때문에 O(N²) 결함은 퇴적성이다. 즉, 동작하는 코드 안에 굳어 있다가 N이 특정 임계값을 넘을 때만 드러난다. 코드는 변경되지 않았다. 코드 주변의 세상이 바뀐 것이다.

MOAD-0001: 퇴적 결함

가장 흔한 사례: 그래프 순회 루프 안에 visited = []를 두는 경우입니다.

visited = []
for node in graph:
if node not in visited:  # O(N) scan each call
visited.append(node)
process(node)

not in visited 호출은 0부터 len(visited)-1까지의 항목을 스캔합니다. N번의 호출 × 평균 N/2개 항목 스캔 = 총 O(N²). 해결책: 한 줄.

visited = set()  # O(1) 멤버십 테스트
for node in graph:
if node not in visited:  # O(1) 해시 조회
visited.add(node)
process(node)

동일한 동작. 동일한 출력. 동일한 테스트 통과. 성장률이 O(N²)에서 O(N)으로 바뀝니다. N=1,000일 때: 1,000배 더 빠름. N=10,000일 때: 10,000배 더 빠름.

해밍 시대가 이를 만든 이유

초기 Java와 C에서는 ArrayList(동적 배열)가 기본 순차 컨테이너였습니다. Set도 존재했지만 관용적이지 않았고, 개발자들은 익숙한 것을 선택했습니다. 1993년 N=50 규모의 그래프 순회에서 visited = []를 사용하면 마이크로초 단위로 실행됐습니다. 그 코드는 버전 관리에 들어가 복사되고, 라이브러리로 감싸지고, 패키지 매니저로 배포됐습니다. 2020년에는 동일한 패턴이 50,000개 노드의 의존성 그래프에서 실행됐습니다.

1993년에는 코드가 올바랐습니다. 세상이 바뀌면서 비용이 커진 것입니다. 해밍 시대는 성장률 질문을 명확히 하지 않음으로써 이런 종류의 결함을 남겼습니다.

진단 및 수정

진단을 적용하세요: O(N²) 패턴을 찾아 수정 방법을 확인하세요.

운영 코드베이스에서 다음 코드를 발견했습니다: `if item not in visited_list: visited_list.append(item)` (50,000개 항목을 순회하는 루프 내부). 전체 루프에서 멤버십 테스트는 평균적으로 몇 번의 연산을 수행하나요? 그리고 `visited_list`를 무엇으로 교체해야 하나요?

어떤 명명 변경

Big O라는 이름이 생기기 전, 프로그래머들은 '이 코드는 느리게 실행된다'는 점을 알아차렸습니다. 그들은 프로파일링을 하고 코드를 다시 작성했습니다. 그러나 그들은 패턴을 가르칠 수 없었고, 단지 사례를 지적할 수밖에 없었습니다. 이름 없는 패턴은 전파될 수 없습니다.

Big O라는 이름이 생긴 후, 선임 엔지니어는 '이것은 O(N²)이므로 세트로 교체하세요'라고 말할 수 있었고, 주니어 엔지니어는 그 패턴을 이해하고 적용하며 다시 가르칠 수 있게 되었습니다. 이름 덕분에 패턴이 지식의 전달 가능한 단위가 되었습니다.

해밍은 다른 분야에서도 이 역학을 알고 있었습니다. 그는 1960년대에 '스파게티 코드'라는 이름을 붙임으로써, 모두가 경험했지만 아무도 이름 붙이지 못했던 결함의 한 부류를 커뮤니티가 인식하고 논의하며 결국 제거할 수 있게 되었다고 설명했습니다. 동일한 메커니즘이 복잡도 클래스에도 적용됩니다.

Unhamming은 해밍이 생략한 어휘를 추가합니다: O(1), O(log N), O(N), O(N log N), O(N²), O(2^N). 이 이름들은 읽는 코드에서 성장 곡선을 보고, 규모에 따른 성능을 예측하며, 수정 사항을 정확히 전달할 수 있게 해줍니다. 이들은 해밍이 말한 기본 개념의 기준 — 지속 가능하며, 나머지 분야의 대부분을 생성할 수 있는 — 을 충족합니다. [TITLE who_coined_big_o/]

From Number Theory to Computer Science

Big O notation은 컴퓨터 과학에서 시작되지 않았습니다. 순수 수학, 특히 수론에서 시작되었으며, Donald Knuth가 알고리즘에 적용하기 74년 전입니다.

Paul Bachmann, 1894

독일 수학자 Paul Bachmann은 1894년 저서 Die Analytische Zahlentheorie (Analytic Number Theory)에서 O 표기법을 처음 소개했습니다. 그는 한 양이 다른 양보다 상수 배 이상 빠르게 증가하지 않는다는 것을 간결하게 표현할 방법이 필요했습니다. 'f(n) = O(g(n))'라고 쓰면, f는 g보다 빠르게 증가하지 않는다는 의미가 됩니다. 이를 통해 수론학자들은 근사의 오차항을 다룰 때 정확한 상수를 추적하지 않고도 추론할 수 있었습니다.

Bachmann은 루프, 데이터 구조, 실행 시간을 생각하지 않았습니다. 그는 소수 분포, 특히 Prime Number Theorem의 오차항에 대해 생각하고 있었습니다.

Edmund Landau, 1909

또 다른 독일 수학자 Edmund Landau는 1909년 저서 Handbuch der Lehre von der Verteilung der Primzahlen (Handbook on the Distribution of Prime Numbers)에서 이 표기법을 널리 알렸습니다. Landau는 관련 표기법인 o (little-o)도 도입했으며, 이 점근 표기법들을 광범위하게 사용한 덕분에 이 표기법들은 Bachmann-Landau notation 또는 간단히 Landau notation으로 불리게 되었습니다.

60년 동안 O 표기법은 수학 분야에만 존재했습니다. 어떤 프로그래머도 이를 생각하지 않았습니다.

도널드 커누스, 1968 & 1976

도널드 커누스는 이 표기법을 컴퓨터 과학으로 옮겨왔습니다. 《The Art of Computer Programming》(Vol. 1, 1968)에서 커누스는 알고리즘의 실행 시간을 설명하기 위해 O 표기법을 사용했습니다. 이는 바흐만의 도구를 새로운 영역으로 직접 이식한 것이었습니다. 그는 알고리즘 분석에 이 표기법을 체계적으로 적용한 최초의 인물이었습니다.

1976년, 커누스는 SIGACT News에 ‘Big Omicron and Big Omega and Big Theta’라는 제목의 짧은 논문을 발표했습니다. 그는 하한을 위한 Omega(Ω)와 엄밀한 경계를 위한 Theta(Θ)를 도입하여, 오늘날 컴퓨터 과학에서 사용하는 세 가지 기호 체계를 완성했습니다. 또한 그는 이 기호들의 사용을 분야 전반에 걸쳐 표준화할 것을 주장했습니다. 이는 의도적인 표준화 조치였으며, 이로 인해 해당 표기법의 채택이 가속화되었습니다.

1980년대 초반까지 Big O는 모든 알고리즘 교과서에 등장했습니다. 1990년대에는 표준 면접 용어가 되었습니다.

74년의 여정

1894 — 바흐만이 수론에서 O를 도입하다
1909 — 란다우가 O, o 및 전체 표기법 체계를 대중화하다
1953 — Hamming이 Bell Labs에서 연구를 시작함 (Big O를 CS 도구로 배우지 못함)
1968 — Knuth가 TAOCP Vol. 1에서 알고리즘 분석에 O를 적용함
1976 — Knuth가 Omega와 Theta를 추가하고 표준화를 주장함
1980s — Big O가 모든 CS 커리큘럼에 포함됨
1993 — MOAD-0001 퇴적층이 프로덕션 코드에 형성됨
1995 — Hamming이 마지막으로 강의를 진행함; Big O를 다루지 않음
2026 — MOAD-0001이 1,000개 이상의 오픈소스 프로젝트에서 발견됨

Bachmann의 도구는 74년 동안 순수 수학 분야에 머물렀습니다. 모든 수학자에게는 보였지만, 모든 프로그래머에게는 보이지 않았습니다. Knuth는 이를 이식할 수 있음을 알아보았습니다. 같은 시대에 같은 컴퓨팅 커뮤니티와 협력했던 Hamming은 이를 자신의 강의에 포함시키지 않았습니다.

Knuth의 표준화가 중요했던 이유 [BLOCK_TYPE SECTION/STEP]

Knuth의 1976년 논문은 Omega와 Theta를 소개하는 것 이상의 일을 했습니다. 그는 해당 분야에 일관된 표기법이 필요하며, 일관되지 않은 표기법이 실제로 해를 끼친다고 주장했습니다. 서로 다른 교과서에서 O를 서로 다른 의미로 사용했습니다. 때로는 상한으로, 때로는 근사치로, 때로는 상수가 중요한지 여부를 명시하지 않고 사용했습니다. Knuth는 이를 정리했습니다. [BLOCK_TYPE SECTION/STEP]

이는 Hamming의 패턴-명명 동역학을 표기법 자체에 적용한 것입니다. Knuth가 기호를 표준화하기 전에는 엔지니어들이 교과서, 논문, 팀 간에 복잡도 주장을 정확하게 전달할 수 없었습니다. 표준화 이후에는 '이 알고리즘은 O(N log N)으로 실행된다'는 표현이 누가 말하든 정확히 하나의 의미를 갖게 되었습니다. [BLOCK_TYPE SECTION/STEP]

Knuth는 또한 비공식적인 해석을 제공했습니다: 'O(f(n))은 충분히 큰 모든 n에 대해 실행 시간이 f(n)의 상수 배 이하라는 의미입니다.' 이 해석 — 상한, 상수 인자까지, 큰 입력에 대해 — 은 모든 프로그래머가 배우는 표준 직관이 되었습니다.

Bachmann은 1894년에 수 이론을 위해 O 표기법을 발명했습니다. Knuth는 1968년에 알고리즘 분석을 위해 이를 채택했습니다. 순수 수학자의 도구가 소프트웨어 엔지니어에게 필수적인 어휘가 되기 위해 컴퓨팅, 규모, 또는 프로그래머의 작업 방식에서 어떤 변화가 필요했을까요? 최소 두 가지 요인을 제시하세요. [BLOCK_TYPE SECTION/STEP]