검수요청.png검수요청.png

해시테이블

위키원
이동: 둘러보기, 검색
해시 테이블로 된 작은 전화 번호부

해시테이블(hash table)은 해시함수를 사용하여 키를 해시값으로 매핑하고, 이 해시값을 인덱스 혹은 주소 삼아 데이터의 값(value)을 키와 함께 저장하여 검색을 빠르게 하기 위한 자료 구조이다. 이 때 데이터가 저장되는 곳을 버킷(bucket) 또는 슬롯(slot)이라고 한다. 해시테이블의 기본 연산은 삽입, 삭제, 탐색이다.

개요

해시테이블은 연관 배열 추상 데이터 유형을 구현하는 데이터 구조로서, 키를 값에 매핑할 수 있는 구조이다. 해시함수를 사용하여 원하는 값을 찾을 수 있는 버킷이나 슬롯의 배열로 인덱스를 계산한다. 이상적으로는 해시함수가 각각의 키를 고유 버킷에 할당하지만, 대부분의 해시 테이블 설계에서는 불완전한 해시함수를 채용하고 있어 해시함수가 둘 이상의 키에 대해 동일한 인덱스를 생성하는 해시 충돌의 원인이 될 수 있다. 적절한 규모의 해시테이블에서, 각 조회의 평균 비용은 표에 저장된 요소의 수와 무관하다. 많은 해시 테이블 설계는 운용당 일정한 평균 비용으로 키 값 쌍을 임의로 삽입과 삭제를 허용한다. 많은 상황에서 해시테이블은 검색 트리나 다른 테이블 조회 구조보다 평균적으로 더 효율적이다. 때문에 해시테이블은 특히 연관 배열, 데이터베이스 색인화, 캐시, 많은 종류의 컴퓨터 소프트웨어에서 널리 사용된다.

Direct-address table

Direct-address table은 키의 전체 개수와 동일한 크기의 버킷을 가진 해시테이블이다. Direct-address table의 장점은 키 개수와 해시테이블 크기가 동일하기 때문에 해시충돌 문제가 발생하지 않는다는 것이다. 하지만 실제 사용하는 키(actucal key)보다 전체 키(unverse of key)보다 훨씬 많은 경우 사용하지 않는 키들을 위한 공간까지 마련해야 하는 탓에 메모리 효율성이 크게 떨어진다. 보통의 경우 다뤄야할 데이터가 정말 많고, 메모리 등 리소스 문제도 생기기 때문에 Direct-address table보다는 해시테이블 크기()가 실제 사용하는 키 개수()보다 적은 해시테이블을 더 선호한다. 이 때 해시테이블의 한 버킷에 평균 몇 개의 키가 매핑되는가를 나타내는 지표로 라고 한다. Direct-address table의 load factor는 1 이하이며, 1보다 큰 경우 해시충돌이 발생하게 된다.[1]

장점

  • 다량의 데이터를 적은 리소스로 관리할 수 있어 효율적이다. 하드디스크나 클라우드에 존재하는 무한에 가까운 데이터(키)들을 유한한 개수의 해시값으로 매핑함으로써 작은 크기의 캐시 메모리로도 프로세스를 관리할 수 있게 된다.
  • 인덱스(index)에 해시값을 사용해서 모든 데이터를 살피지 않아도 삽입/삭제을 편하게 수행할 수 있다.
  • 언제나 동일한 해시값을 리턴하고, 해당 인덱스만 알면 해시테이블의 크기에 상관없이 데이터에 빠르게 접근할 수 있으며, 인덱스는 계산이 간단한 함수(상수시간)로 작동하기 때문에 매우 효율적이다. 다시 말해, 데이터 액세스 시 계산복잡성으로 0(1)을 지향한다.
  • 키와 해시값 사이에 직접적인 연관이 없기 때문에 해시값만 가지고는 키를 온전히 복원하기 어려워 보안 분야에서 널리 사용된다.
  • 길이가 서로 다른 입력데이터에 대해 일정한 길이의 출력을 만들 수 있어서 데이터를 축약할 수도 있다.

문제점

  • 해시테이블에서의 연산은 평균적으로 일정한 시간이 걸리지만 좋은 해시 함수의 비용은 순차 목록 또는 검색 트리에 대한 검색 알고리즘의 내부 루프보다 상당히 클 수 있다. 따라서 해시 테이블은 항목 수가 매우 적으면 유효하지 않는다.(해시 함수를 계산하는데 드는 높은 비용은 해시값을 키와 함께 저장하여 완화 할 수 있음)
  • 맞춤법 검사와 같은 특정 문자열 처리 응용 프로그램의 경우 해시테이블은 트리, 유한 오토마타 또는 주디 배열보다 효율적이지 않을 수 있다. 또한 저장할 수 있는 키가 너무 많지 않은 경우 즉, 각 키를 충분히 작은 비트수로 표현할 수 있는 경우 해시테이블 대신 키를 배열의 인덱스로 직접 사용할 수 있다. 이 경우에는 충돌이 발생하지 않는다.
  • 해시테이블에 저장된 항목은 효율적으로(항목 당 일정한 비용으로) 열거되지만 의사 임의의 순서로만 열거 할 수 있다. 따라서 키가 지정된 키와 가장 가까운 항목을 찾는 효율적인 방법은 없다. 특정 순서로 모든 n개 항목을 나열하려면 일반적으로 비용이 항목 당 log(n)에 비례하는 별도의 정렬 단계가 필요하다. 이에 비해 정렬 검색 트리는 조회 및 삽입 비용이 log(n)에 비례하지만 거의 동일한 비용으로 가장 가까운 키를 찾을 수 있으며 입력 당 일정한 비용으로 모든 항목을 나열한 순서가 매겨진다.
  • 해시함수가 충돌하지 않기 때문에 키가 저장되어 있지 않으면 주어진 순간에 테이블에 있는 키를 쉽게 열거할 수 없다.
  • 작업당 평균 비용이 일정하고 상당히 작지만, 단일 작업의 비용은 상당히 높을 수 있다. 특히 해시테이블이 동적 크기 조정을 사용하는 경우 삽입 또는 삭제 작업은 때때로 항목 수에 비례하여 시간이 걸릴 수 있다. 이는 실시간 또는 인터렉티브 애플리케이션에서 심각한 단점이 될 수 있다.
  • 해시테이블은 일반적으로 참조의 지역성이 낮다. 즉, 액세스 할 데이터는 임의로 메모리에서 무작위로 분산되어 있다. 해시테이블이 액세스 패턴을 야기하기 때문에 긴 지연을 유발하는 마이크로 프로세서 캐시 미스가 발생할 수 있다. 선형 검색으로 검색된 배열과 같은 소형 데이터 구조는 테이블이 비교적 작고 키가 소형인 경우 더 빠를 수 있다. 최적의 성능 포인트는 시스템마다 다르다.
  • 해시테이블은 많은 충돌이 있을 때 매우 비효율적이다. 극단적으로 고르지 않은 해시 분포가 우연히 발생 할 가능성은 거의 없지만 해시 함수에 대해 잘 알고 있는 악의적인 공격자는 과도한 충돌로 인해 최악의 행동을 일으키는 정보를 해시에 제공할 수 있다. 예를 들어, 서비스 거부 공격과 같은 매우 낮은 성능을 유발할 수 있다. 중요한 애플리케이션에서 최악의 경우 보증이 더 나은 데이터 구조를 사용할 수 있지만, 범용 해싱은 공격자가 어떤 입력으로 최악의 행동을 유발하는지 예측할 수 없게 하는 무작위 알고리즘이 선호될 수 있다. 리눅스 라우팅 테이블 캐시의 해시테이블에서 사용된 해시 함수는 이러한 공격에 대한 대책으로 리눅스 버전 2.4.2에서 변경되었다.

활용

연관배열

해시테이블은 일반적으로 여러 유형의 메모리 내 테이블을 구현하는데 사용된다. 특히 루비, 파이썬, PHP와 같은 해석된 프로그래밍 언어에서 연관배열(지표가 임의의 문자열 또는 기타 복잡한 객체인 배열)을 구현하는데 사용된다.

멀티맵에 새 항목을 지정하고 해시 충돌이 발생하면 멀티맵은 두 항목을 모두 무조건 사용한다. 새 항목을 일반적인 연관배열에 저장하고 해시충돌이 발생하지만 실제 키 자체가 다른 경우 연관배열도 마찬가지로 두 항목을 모두 저장한다. 그러나 새 항목의 키가 이전 항목의 키와 정확하게 일치하는 경우 연관배열은 일반적으로 이전 항목을 지우고 새 항목으로 덮어 쓰기 때문에 테이블의 모든 항목은 고유 키를 갖는다.

데이터베이스 색인화

해시테이블은 디스크 기반 데이터 구조 및 데이터베이스 인덱스(예:dbm)로도 사용될 수 있지만 B- 트리는 이러한 응용 프로그램에서 더 많이 사용된다. 다중 노드 데이터베이스 시스템에서 해시테이블은 일반적으로 노드 사이에 행을 분산하는 데 사용되어 해시조인에 대한 네트워크 트래픽을 줄인다.

캐시

해시테이블은 느린 미디어에 주로 저장된 데이터에 대한 액세스 속도를 높이기 위해 사용되는 캐시, 보조 데이터 테이블을 구현하는데 사용할 수 있다. 이 응용 프로그램에서는 충돌하는 두 항목 중 하나를 삭제하여 해시충돌을 처리할 수 있다. 일반적으로 현재 테이블에 저장된 이전 항목을 지우고 새 항목으로 덮어 쓰므로 테이블의 모든 항목은 고유한 해시값을 갖는다.

세트

주어진 키를 가지고 있는 항목을 복구하는 것 외에도, 많은 해시테이블 구현들은 그러한 항목이 존재 여부를 구별할 수 있다. 따라서 이러한 구조는 특정 키가 특정 키 집합에 속하는지 여부를 기록하는 세트 데이터 구조를 구현하는 데 사용될 수 있다. 이 경우 입력값과 관련된 모든 부분을 제거함으로써 구조를 단순화 할 수 있다. 해시는 정적 집합과 동적 집합을 구현하는 데 사용될 수 있다.

개체 표현

, 파이썬, 자바스크립트, 루아, 루비와 같은 몇몇 동적 언어는 해시테이블을 사용하여 개체를 구현한다. 이 표현에서 는 개체의 구성원과 메소드의 이름이며, 값은 해당 구성원이나 메소드에 대한 포인터가 된다.

독특한 데이터 표현

해시테이블은 같은 내용을 가진 다중 문자열 생성을 피하기 위해 일부 프로그램에서 사용할 수 있다. 이를 위해 프로그램에서 사용중인 모든 문자열은 해시테이블로 구현된 단일 문자열 풀에 저장되며, 이 문자열 풀은 새 문자열을 만들어야 할 때마다 확인된다. 이 기법은 해시컨설팅이라는 이름으로 Lisp 인터프리터에 도입되었으며, 다른 많은 종류의 데이터(심볼릭 대수 시스템의 표현트리, 데이터베이스의 레코드, 파일 시스템의 파일, 이진법 결정 다이어그램 등)와 함께 사용할 수 있다.

각주

  1. ratsgo, 〈해싱, 해시함수, 해시테이블〉, 《개인 블로그》, 2017-10-25

참고자료

같이 보기


  검수요청.png검수요청.png 이 해시테이블 문서는 블록체인 기술에 관한 글로서 검토가 필요합니다. 위키 문서는 누구든지 자유롭게 편집할 수 있습니다. [편집]을 눌러 문서 내용을 검토·수정해 주세요.