"O(1) 조회는 영원히 공짜가 아니야 — 너무 붐비기 전에 해시맵이 조용히 자기를 키워서 지키는 약속이야. 키우는 걸 멈추면 약속이 깨져."
부하율
부하율 (load factor) 은 저장된 항목 대 가용 슬롯의 비율이야: load = entries / slots. 해시맵 건강을 예측하는 단 하나의 숫자야. 낮은 부하 (가령 0.3) 에선 키가 얇게 퍼져, 충돌이 드물고, 조회가 깔끔하게 O(1). 부하가 1 쪽으로 오르면, 슬롯이 차고, 충돌이 쌓이고, 체인이 길어지고 (또는 탐사 순서가 늘어나고), 네 O(1) 이 조용히 O(n) 쪽으로 썩어. 부하율은 계기판의 게이지야 — 그걸 보면 맵이 건강한지 알아.
고침: 키우고 리해시
부하율이 임계값을 넘으면, 맵이 리사이즈해: 더 큰 테이블 (보통 두 배) 을 할당하고 기존 모든 항목을 거기로 리해시해. 왜 복사 말고 리해시? 슬롯 인덱스가 hash % size 인데 size 가 방금 바뀌어서 — 모든 키가 새 테이블용으로 인덱스를 다시 계산해야 해. 리해싱은 O(n) 연산이야. 근데 — 이 영화 정확히 봤지 — 테이블이 두 배가 되니까, 리사이즈가 지수적으로 덜 일어나, 그래서 모든 삽입에 펴 바른 O(n) 비용이 삽입당 분할 상환 O(1) 으로 평균 나. Complexity 트랙의 동적 배열 두 배 하기 이야기가, 한 층 위에서 펼쳐지는 거야.
임계값이 앉는 자리
맞는 임계값은 충돌 전략에 달렸어. 체이닝은 1 넘는 부하를 견뎌 (체인이 좀 길어질 뿐), 그래서 더 차게 굴릴 수 있어. 개방 주소법은 차면 가파르게 떨어져 — 꽉 차기 직전 탐사 순서가 폭발 — 그래서 더 일찍 리사이즈해야 해; CPython 의 dict 는 부하를 대략 2/3 미만으로 유지해. 그 2/3 규칙이 정확히 Python dict 가 키 추가할 때 가끔 멈춰 리사이즈하는 이유고, 항목 수가 암시하는 것보다 눈에 띄게 메모리를 더 쓰는 이유야. 빈 슬롯은 낭비가 아니라 — 조회를 O(1) 로 유지하는 숨 쉴 공간이야.