오픈 주소 해시 테이블의 삭제를 간단히 구현하는 방법

이 논문은 체이닝 방식과 달리 오픈 주소법에서 삭제 시 “deleted” 마크를 사용하지 않고도 올바른 탐색을 유지할 수 있는 새로운 삭제 알고리즘을 제안한다. 기존 3‑state(빈, 사용, 삭제) 방식의 단점을 보완하고, Java 구현 코드를 통해 실용성을 입증한다.

오픈 주소 해시 테이블의 삭제를 간단히 구현하는 방법

초록

이 논문은 체이닝 방식과 달리 오픈 주소법에서 삭제 시 “deleted” 마크를 사용하지 않고도 올바른 탐색을 유지할 수 있는 새로운 삭제 알고리즘을 제안한다. 기존 3‑state(빈, 사용, 삭제) 방식의 단점을 보완하고, Java 구현 코드를 통해 실용성을 입증한다.

상세 요약

오픈 주소 해시 테이블은 충돌 해결을 위해 빈 슬롯을 찾아 이동하면서 데이터를 저장한다. 이때 삭제를 단순히 슬롯을 “빈”으로 표시하면, 동일 해시값을 가진 다른 키가 그 뒤에 위치했을 경우 검색이 중단돼 찾지 못하는 오류가 발생한다. 전통적인 해결책은 슬롯을 “삭제됨”(deleted) 상태로 표시해 탐색 경로를 유지하는 것이지만, 이는 추가적인 메모리 오버헤드와 복잡한 재해시(rehash) 시점 판단을 야기한다. 논문은 이러한 “deleted” 마크를 완전히 배제하고, 삭제된 원소를 주변의 다른 원소와 교환하면서 해시 테이블의 탐색 연속성을 보존하는 알고리즘을 제시한다. 핵심 아이디어는 삭제된 슬롯을 “빈”으로 만들고, 그 뒤에 위치한 원소들 중 해시값이 현재 슬롯보다 앞에 있는(즉, 원래 해시 위치가 현재 슬롯보다 앞에 있던) 원소를 뒤로 이동시켜 빈 슬롯을 메꾼다. 이를 위해 삭제 시점부터 테이블 끝까지 순차적으로 검사하면서, 각 원소의 원래 해시 인덱스와 현재 인덱스 사이의 거리 관계를 판단한다. 만약 원소가 현재 빈 슬롯보다 “앞”에 있어야 한다면, 그 원소를 빈 슬롯으로 이동시키고, 새롭게 비어진 슬롯을 다시 같은 방식으로 처리한다. 이 과정은 빈 슬롯이 테이블의 끝에 도달하거나, 더 이상 이동 가능한 원소가 없을 때까지 반복된다.

알고리즘의 시간 복잡도는 최악의 경우 O(m) (m은 테이블 크기)이며, 평균적인 경우에는 삭제된 원소 주변에 몇 개의 원소만 이동하면 되므로 거의 O(1)에 가깝다. 메모리 측면에서는 추가적인 상태 플래그가 필요 없으므로 슬롯당 저장 공간이 최소화된다. 또한, “deleted” 마크가 남아 있지 않기 때문에 재해시 시점 판단이 단순해지고, 삭제 후 즉시 삽입 연산이 가능해 전체 시스템의 응답성이 향상된다.

논문은 Java 코드로 구현된 예시를 제공한다. 핵심 메서드는 delete(key)이며, 내부적으로 findSlot(key)를 통해 키가 존재하는 슬롯을 찾고, 그 슬롯을 “빈”으로 만든 뒤 shiftDelete(pos)라는 루프를 실행한다. shiftDelete는 현재 위치부터 시작해 다음 슬롯을 검사하고, 해당 슬롯에 저장된 원소의 원래 해시 인덱스(hash(key))와 현재 인덱스 사이의 순환 거리((i - hash) mod m)를 계산한다. 이 거리가 현재 빈 슬롯까지의 거리보다 크면 원소를 빈 슬롯으로 이동시키고, 빈 슬롯을 새 위치로 업데이트한다. 루프는 빈 슬롯이 연속적으로 발생하지 않을 때까지 진행된다.

실험 결과는 제시되지 않았지만, 논문은 이 방법이 “deleted” 플래그 기반 방법보다 구현이 간단하고, 메모리 사용량이 적으며, 삭제 후 즉시 삽입이 가능하다는 장점을 강조한다. 또한, 이 알고리즘은 선형 탐색(linear probing)뿐 아니라 이차 탐색(quadratic probing)이나 이중 해싱(double hashing)과 같은 다른 오픈 주소 탐색 전략에도 적용 가능하다고 주장한다.

이와 같은 접근은 해시 테이블 구현에서 흔히 간과되는 “삭제 후 재배치” 문제를 근본적으로 해결함으로써, 시스템 수준에서 메모리 효율성과 성능을 동시에 개선할 수 있는 실용적인 대안으로 평가된다.


📜 논문 원문 (영문)

🚀 1TB 저장소에서 고화질 레이아웃을 불러오는 중입니다...