-
1분할상환분석 심화 DONE
분할상환분석은 연산 하나하나의 최악 비용이 아니라 n번 연산의 총비용을 보는 분석이다. 포텐셜 함수법은 자료구조의 상태를 실수 하나 Φ로 요약하고, 각 연산의 분할상환 비용을 실제 비용에 포텐셜 변화량을 더한 값으로 정의한다.
How it works이 정의 덕분에 n번 연산의 총 분할상환 비용을 더하면 중간 항이 전부 telescoping으로 소거되어, Φ가 0 이상이고 초기값이 0이면 분할상환 비용의 합이 실제 비용의 합의 상한이 된다. 동적 배열이 가득 찰 때마다 2배로 늘리는 doubling 전략에 Φ = 2·num − size를 잡으면, 복사가 일어나는 비싼 삽입도 매번 상수 시간 3으로 상각된다.
Why"평균적으로 O(1)"이라는 말이 운이 아니라 수학적으로 보장된다는 걸 증명해야, 시스템이 가끔 비싼 연산을 감당할 수 있는지 설계 단계에서 판단할 수 있기 때문이다.
Detail →
-
2균형 트리 계열 비교 DONE
Red-Black 트리·B+Tree·Skip List는 전부 정렬된 키를 O(log n)에 다루는 사전 자료구조지만, 실제로 갈리는 축은 복잡도가 아니라 디스크·동시성이다. 균형 트리에서 정말 비싼 연산은 탐색이 아니라 회전이고, 회전은 여러 노드를 원자적으로 바꿔야 해서 락 범위가 조상 쪽으로 넓어진다.
How it worksSkip List는 균형을 구조적으로 유지하는 대신 삽입할 때 동전을 던져 레벨을 정해 확률로 사는데, 회전이 아예 없으므로 삽입이 지역적이라 CAS만으로 락프리 구현이 가능하다. B+Tree는 노드 하나에 페이지 크기만큼 많은 키를 담아 디스크 지역성을 얻는 대신 회전 없이 노드 분할·병합으로 균형을 유지한다.
Why락을 어디에 얼마나 잡는가와 한 노드에 키를 몇 개 담는가가 그 자료구조가 동시 쓰기가 많은 시스템에서 쓸 수 있는지 없는지를 가르기 때문이다.
Detail →
-
3영속(persistent) 자료구조와 구조 공유 DONE
영속(persistent) 자료구조는 갱신 연산이 기존 버전을 파괴하지 않고 새 버전을 만들며, 이전 버전도 계속 조회 가능한 자료구조다. 핵심 기법은 구조 공유로, 변경된 경로 위의 노드만 새로 복사하고 나머지 서브트리는 이전 버전과 포인터를 그대로 공유한다.
How it works균형 트리나 트라이 기반 구조에서는 루트부터 변경 지점까지의 경로 길이가 O(log n)이므로 갱신 한 번의 시간과 추가 메모리도 O(log n)에 머문다. 과거 버전을 읽기만 가능한 부분 영속성과 과거 버전에서 다시 갱신까지 가능한 완전 영속성을 구분하며, 함수형 언어의 불변 리스트나 HAMT(hash array mapped trie)가 대표 사례다.
Why롤백, 스냅샷 격리, undo, 낙관적 동시성처럼 여러 버전을 동시에 살아 있게 해야 하는 시스템에서 매 갱신마다 전체 복사를 하면 O(n) 비용이 나기 때문이다.
Detail →
-
4함수형 업데이트와 상태 diff
함수형 업데이트는 기존 자료구조를 변형하지 않고 변경분만 반영한 새 버전을 만들어 반환하는 방식이다. 이를 값싸게 하는 핵심 기법이 path copying으로, 루트에서 수정 지점까지의 경로에 있는 노드만 복사하고 나머지 서브트리는 이전 버전과 포인터로 공유한다(structural sharing).
How it works균형 트리나 HAMT 같은 트라이 계열에서는 경로 길이가 O(log n)이므로 한 번의 업데이트 비용도 O(log n) 노드 복사로 억제된다. 대신 진짜 비용은 점근 복잡도가 아니라 상수항에 숨어 있다.
Why불변 상태를 쓰는 프론트엔드·상태머신 코드에서 "복사는 O(log n)이니 공짜"라고 믿다가 GC 스파이크와 캐시 미스로 처리량이 무너지는 일이 흔하다. 반대로 diff를 참조 비교로 처리할 수 있다는 점은 리렌더·변경 전파 최적화의 근거가 된다.
Detail →
-
5Verkle tree
트라이는 키를 문자 단위로 쪼개 경로로 표현하는 자료구조이고, 패트리샤 트라이는 자식이 하나뿐인 연속 구간을 하나의 간선으로 압축(path compression)해 깊이를 줄인 변형이다. 이더리움의 Merkle Patricia Trie(MPT)는 여기에 머클 해시를 얹어, 각 노드가 자식들의 해시를 담고 부모는 그 해시들을 다시 해시하는 방식으로 상태 전체를 하나의 루트 해시로 커밋한다.
How it worksMPT의 분기 노드는 니블(4비트) 단위라 자식이 최대 16개이므로, 한 노드의 증명에는 형제 해시들이 모두 들어가고 증명 크기는 대략 (경로 깊이 × 분기 폭)에 비례해 커진다. Verkle 트라이는 해시 대신 벡터 커밋먼트(다항식 커밋먼트 계열)를 써서 한 노드의 자식 전체를 상수 크기 커밋먼트 하나로 묶고, 열람 증명도 상수 크기에 가깝게 만든다.
Why상태 증명 크기는 라이트 클라이언트와 stateless 검증의 대역폭을 직접 결정하고, 갱신 비용은 풀노드의 블록 처리 시간을 결정한다. 어느 쪽을 깎을지 모르면 스토리지 계층 설계나 증명 기반 기능의 실현 가능성을 판단할 수 없다.
Detail →
-
6확률적 자료구조
확률적 자료구조는 정확한 답 대신 제한된 오차를 허용하는 대가로 메모리를 크게 줄이는 구조다. Bloom filter는 비트 배열과 k개의 해시 함수를 써서 원소 포함 여부를 판정하며, 거짓 양성은 있지만 거짓 음성은 없고 원소 삭제도 되지 않는다.
How it worksCuckoo filter는 원소 대신 짧은 지문(fingerprint)을 두 후보 버킷 중 하나에 넣는 방식이라 삭제를 지원한다. Count-Min sketch는 여러 해시 행의 카운터 배열로 빈도를 추정하며, 충돌 때문에 과대추정은 하지만 과소추정은 하지 않는다.
Why로그·멤풀·캐시처럼 원소가 수억 개인 곳에서 정확한 집합이나 카운터를 그대로 들고 있으면 메모리가 먼저 터진다.
Detail →
-
7스트리밍/스케치 알고리즘
스트리밍 알고리즘은 데이터를 한 번(또는 몇 번) 순차적으로만 훑으면서, 입력 크기보다 훨씬 작은 공간으로 근사 답을 내는 알고리즘이다. 정확한 답을 내려면 서로 다른 원소 수에 비례하는 메모리가 필요하다는 하한이 있기 때문에, 대신 오차와 실패확률을 파라미터로 받아 확률적 보장을 주는 스케치 자료구조를 쓴다.
How it worksheavy hitters(빈도 상위 원소 찾기)는 Misra-Gries처럼 카운터를 고정 개수만 유지하며 일괄 감소시키는 방식이나, Count-Min Sketch처럼 여러 해시 함수로 2차원 카운터 배열에 더하고 최솟값을 추정치로 쓰는 방식으로 푼다. 근사 분위수는 t-digest, KLL 같은 구조가 표본을 계층적으로 압축해 원하는 분위수를 오차 범위 안에서 답한다.
Why로그·메트릭·주문 흐름처럼 전량 저장이 불가능한 데이터에서 상위 사용자, p99 지연 같은 값을 실시간으로 알아야 할 때 정확 집계는 메모리에서 먼저 무너진다.
Detail →
-
8순서 통계
순서 통계란 배열을 정렬했을 때 k번째로 작은 원소를 뜻하며, 전체 정렬 없이 그 원소만 찾는 문제를 선택 문제라 한다. Quickselect는 퀵정렬의 분할을 재사용하되 피벗이 속한 한쪽 구간만 재귀하므로 기대 시간이 선형이지만, 피벗이 계속 치우치면 최악에는 제곱 시간이 된다.
How it works중위수의 중위수는 원소를 5개씩 묶어 각 그룹의 중위수를 구하고 그 중위수들의 중위수를 피벗으로 삼아, 매 단계에서 일정 비율 이상의 원소가 확실히 제거되도록 보장한다. 이 보장 덕분에 재귀식이 선형으로 풀려 최악에도 선형 시간이 되지만 상수 계수가 커서 실무에서는 느리다.
Whyp99 지연을 계산하거나 상위 N개를 뽑는 작업에서 전체 정렬을 돌리면 불필요한 로그 배수를 지불하게 되고, 순진한 Quickselect는 적대적 입력에서 최악 케이스로 끌려갈 수 있다.
Detail →
-
9문자열 인덱스
서픽스 배열은 문자열의 모든 접미사를 사전순으로 정렬한 뒤 그 시작 위치만 배열로 보관하는 인덱스이다. 정렬돼 있으므로 임의의 패턴 검색을 이분 탐색으로 처리할 수 있고, 인접한 접미사의 공통 접두사 길이를 담은 LCP 배열을 함께 두면 반복 부분문자열, 서로 다른 부분문자열 개수 같은 질의도 선형에 가깝게 풀린다.
How it works서픽스 오토마톤(DAWG)은 같은 정보를 상태 기계로 표현한 것으로, 문자열의 모든 부분문자열을 인식하는 최소 결정적 오토마톤이며 상태 수가 입력 길이에 선형으로 유지된다. 오토마톤은 온라인으로 한 글자씩 추가하며 만들 수 있어 스트리밍에 유리하고, 서픽스 배열은 메모리가 조밀해 대용량 정적 텍스트에 유리하다.
Why로그·트레이스처럼 텍스트는 고정돼 있는데 검색은 수없이 반복되는 상황에서, grep식 선형 스캔은 데이터가 커지는 순간 그대로 비용이 된다.
Detail →
-
10세그먼트 트리 심화
세그먼트 트리는 배열 구간에 대해 결합법칙이 성립하는 연산(합, 최솟값, gcd 등)을 O(log n)에 질의·갱신하는 이진 트리 구조다. Lazy propagation은 구간 전체를 갱신할 때 각 노드에 "아직 자식에게 내려보내지 않은 연산"을 보류값으로 저장하고, 그 자식을 실제로 방문하는 시점에 밀어내려 구간 갱신도 O(log n)에 처리한다.
How it works이 기법이 성립하려면 보류 연산끼리 합성 가능해야 하고, 구간 크기에 따라 노드 값에 어떻게 반영되는지가 정의되어야 한다(예: 구간 덧셈이면 합에 delta 곱하기 구간 길이를 더한다). 영속(persistent) 세그먼트 트리는 갱신 시 루트에서 잎까지의 경로에 있는 O(log n)개 노드만 새로 만들고 나머지 서브트리는 이전 버전과 공유하는 path copying 기법으로, 모든 과거 버전을 O(log n) 추가 공간에 보존한다.
Why롤백이나 시점 스냅샷이 필요한 상태 집계, 그리고 구간 갱신이 대량으로 들어오는 워크로드에서 naive 구현은 갱신당 O(n)으로 무너진다.
Detail →
-
11위상정렬·DAG 스케줄링
위상정렬은 방향 비순환 그래프(DAG)의 정점을 모든 간선 u→v에 대해 u가 v보다 앞서도록 나열하는 것이다. Kahn 알고리즘은 진입차수 0인 정점을 큐에 넣고 꺼낼 때마다 인접 정점의 진입차수를 줄이는 방식으로 O(V+E)에 이를 계산하며, 큐가 비었는데 남은 정점이 있으면 사이클이 존재한다는 뜻이다.
How it works스케줄링 관점에서는 위상정렬의 각 단계, 즉 동시에 진입차수가 0이 되는 정점 집합을 하나의 병렬 레이어로 묶을 수 있고, 이때 레이어 수는 DAG의 최장 경로 길이와 같다. 따라서 프로세서가 무한히 많아도 실행 시간의 하한은 최장 경로(critical path)이며, 이것이 병렬 스케줄의 근본 한계다.
Why블록 내 트랜잭션을 병렬로 돌리려는 모든 설계는 결국 '충돌 그래프의 최장 경로'라는 한계에 부딪히므로, 병렬화로 얻을 수 있는 최대 이득을 미리 추정하려면 이 계산이 필요하다.
Detail →
-
12최대 유량·최소 컷과 매칭
유량 네트워크는 각 간선에 용량이 있는 방향 그래프이고, 소스에서 싱크로 보낼 수 있는 최대 유량을 구하는 문제가 최대 유량 문제다. 최대 유량-최소 컷 정리는 소스와 싱크를 분리하는 컷 중 용량 합이 최소인 값이 최대 유량과 정확히 같다고 말하며, 이는 선형계획법 쌍대성의 조합론적 사례다.
How it works알고리즘은 잔여 그래프(residual graph)에서 증가 경로를 찾아 유량을 밀어 넣는 방식이 기본이고, 경로 선택 전략에 따라 Edmonds-Karp(최단 증가 경로)나 Dinic(레벨 그래프 + 블로킹 유량)으로 나뉜다. 이분 매칭은 모든 용량을 1로 둔 유량 문제로 환원되며, 이때 최대 매칭 크기가 최소 정점 덮개 크기와 같다는 König 정리가 최소 컷 정리의 특수형으로 따라 나온다.
Why스케줄링, 주문 배정, 노드-샤드 할당처럼 "누구에게 무엇을 얼마나" 문제가 나오면 대부분 유량 또는 매칭으로 환원되며, 잘못 모델링하면 지수 시간 탐색을 짜게 된다.
Detail →
-
13선형계획과 쌍대성 직관
선형계획(LP)은 선형 부등식 제약 아래에서 선형 목적함수를 최대화하거나 최소화하는 문제이며, 실행가능 영역은 볼록 다면체이고 최적해가 존재하면 그 꼭짓점에서 달성된다. 모든 LP에는 짝이 되는 쌍대(dual) 문제가 있고, 약쌍대성은 임의의 쌍대 실행가능해가 원문제 최적값의 한계를 준다는 것, 강쌍대성은 양쪽이 모두 실행가능하면 두 최적값이 일치한다는 것이다.
How it works쌍대 변수는 각 제약의 잠재가격(shadow price), 즉 그 제약을 한 단위 완화했을 때 목적값이 얼마나 개선되는지를 뜻한다. 상보여유 조건은 여유가 남는 제약의 잠재가격은 0이고, 양의 가격이 붙은 제약은 반드시 타이트하다는 관계를 말한다.
Why경매나 블록스페이스 배분처럼 희소 자원을 나누는 문제에서, 배분의 최적성 증명과 참가자에게 물릴 가격이 같은 쌍대 구조에서 나온다는 사실을 알아야 논쟁을 수치로 끝낼 수 있다.
Detail →
-
14랜덤화·근사 알고리즘
많은 조합 최적화 문제는 변수에 0 또는 1만 허용하는 정수계획(IP)으로 정확히 표현되지만 IP 자체는 NP-hard다. LP 완화는 이 정수 제약을 0 이상 1 이하의 실수 구간으로 느슨하게 풀어 다항 시간에 최적해를 구하는 기법이며, 완화한 최적값은 원 문제 최적값의 한계(하한 또는 상한)를 준다.
How it works랜덤 라운딩은 이렇게 얻은 분수해 x_i를 "i를 선택할 확률"로 해석해 독립적으로 동전을 던져 정수해로 되돌린다. 기댓값 계산과 집중 부등식으로 결과가 LP 최적값의 일정 배 안에 들어옴을 보이면 근사비가 증명된다.
Why실무의 스케줄링·배치·매칭 문제는 대부분 NP-hard라 최적해를 고집하면 풀리지 않고, 성능 보장이 있는 근사해를 언제 받아들일지 판단하는 근거가 필요하다. 또 LP 완화값은 휴리스틱 해가 최적에서 얼마나 떨어졌는지 재는 무료 기준선이 된다.
Detail →
-
15온라인 알고리즘과 경쟁비
온라인 알고리즘은 입력 전체를 미리 보지 못하고 요청이 도착할 때마다 되돌릴 수 없는 결정을 내려야 하는 알고리즘이다. 성능은 절대 비용이 아니라 경쟁비로 재는데, 임의의 입력열에 대해 (온라인 알고리즘의 비용) / (모든 입력을 아는 오프라인 최적의 비용)의 최악값으로 정의된다.
How it works캐시 교체(페이징)에서는 크기 k인 캐시에 대해 LRU와 FIFO가 k-경쟁적이고, 결정론적 알고리즘의 경쟁비 하한도 k라서 LRU는 이 부류에서 최적이다. 무작위화를 허용하면 마킹 알고리즘처럼 기댓값 기준 경쟁비를 로그 규모로 낮출 수 있는데, 이는 적대적 입력이 알고리즘의 다음 수를 예측하지 못하게 만들기 때문이다.
Why캐시, 커넥션 풀, 실시간 입찰, 주문 매칭처럼 '미래를 모른 채 지금 결정해야 하는' 코드는 어디에나 있는데, 평균 케이스 직관만으로는 적대적 트래픽에서 무너진다. 경쟁비는 그 최악을 정량화해 주는 유일한 언어다.
Detail →
-
16NP-난해와 환원
환원은 문제 A의 인스턴스를 다항 시간에 문제 B의 인스턴스로 바꾸는 변환이며, A가 B로 환원되면 B가 A보다 쉽지 않다는 뜻이다. NP-완전은 NP에 속하면서 NP의 모든 문제가 그 문제로 환원되는 문제이고, NP-난해는 NP 소속 여부와 무관하게 그만큼 어려운 문제를 가리킨다.
How it works새로운 문제가 어렵다는 것을 보이는 표준 방법은 이미 알려진 NP-완전 문제를 그 문제로 환원하는 것이다. P와 NP가 다르다면 NP-완전 문제에 다항 시간 정확 알고리즘은 존재하지 않는다.
Why어려움의 근거를 모르면 본질적으로 불가능한 최적화를 계속 튜닝하며 시간을 태우거나, 반대로 쉽게 풀리는 특수 구조를 못 알아보고 성급히 포기한다.
Detail →
-
17병렬 알고리즘 모델
work-span 모델은 병렬 계산을 DAG로 보고 두 값으로 요약한다. work T1은 전체 연산량(프로세서 1개로 걸리는 시간), span T∞는 의존성 사슬의 임계 경로 길이(프로세서가 무한히 많아도 못 줄이는 시간)이며, 병렬성은 T1/T∞로 정의된다.
How it works좋은 스케줄러(예: work-stealing)는 Tp가 대략 T1/p + T∞ 수준임을 보장하므로, 병렬성이 p보다 충분히 커야 선형 스케일에 가까워진다. Amdahl의 법칙은 문제 크기를 고정한 채 직렬 비율 s가 있으면 속도향상이 1/s로 상한이 걸린다고 말한다.
Why코어를 늘렸는데 성능이 안 오를 때, 원인이 직렬 구간인지 임계 경로인지 스케줄링 오버헤드인지 구분하지 못하면 엉뚱한 곳을 튜닝하게 된다.
Detail →
-
18조합 생성·그레이 코드·순열 열거 (TAOCP 4권)
조합적 대상의 열거란 부분집합, 조합, 순열 같은 구조를 중복 없이 빠짐없이 하나씩 생성하는 기법이다. 그레이 코드는 연속한 두 코드가 정확히 한 비트만 다르도록 부분집합을 나열하는 순서이며, 반사 이진 그레이 코드는 인덱스 i에 대해 i와 i를 오른쪽으로 한 칸 시프트한 값의 XOR로 간단히 얻는다.
How it works순열은 사전순으로 다음 순열을 만드는 방법이나, 매 단계 인접 두 원소만 교환하며 모든 순열을 생성하는 방식으로 열거할 수 있다. 이런 최소 변화 열거의 핵심 이점은 이전 상태에서 한 번의 작은 갱신으로 다음 상태의 평가값을 증분 계산할 수 있다는 것이다.
Why테스트 벡터 생성, 퍼징 시드 설계, 작은 상태 공간의 완전 탐색에서 중복이나 누락 없이 전수를 도는 것이 곧 검증의 신뢰도이고, 최소 변화 순서를 쓰면 상태 되감기 비용이 사라진다.
Detail →
-
19[복습] 알고리즘 선택의 실전 기준표
알고리즘 선택은 점근 복잡도만으로 결정되지 않고, 입력 규모, 데이터 분포, 접근 패턴, 메모리 계층, 갱신 빈도, 최악 대 평균 요구사항이라는 축들의 조합으로 결정된다. 예를 들어 n이 작으면 상수가 작은 O(n^2)가 O(n log n)을 이기고, 데이터가 거의 정렬돼 있으면 적응적 정렬이 유리하며, 캐시 지역성이 좋은 배열 기반 구조가 포인터 추적 구조보다 실측에서 앞서는 일이 흔하다.
How it works읽기 위주면 정적 인덱스, 쓰기 위주면 로그 구조나 상환 분석이 좋은 구조를 고른다. 지연시간 꼬리(p99)가 중요하면 평균이 좋아도 최악이 나쁜 상환 알고리즘은 피해야 한다.
Why실무 성능 사고의 상당수는 잘못된 알고리즘이 아니라 제약을 잘못 짚은 선택에서 나오고, 그 비용은 코드가 굳은 뒤에 드러난다.
Detail →