David Richerby의 답변을 확장하기 위해 " 해시 함수 " 라는 용어 는 약간 오버로드되었습니다. 종종 해시 함수에 대해 이야기 할 때 MD5, SHA-1 또는 Java의 .hashCode()
메소드 와 같은 것을 생각하며 일부 입력을 단일 숫자로 바꿉니다. 그러나이 숫자의 도메인은 당신이 데이터를 저장하는 데 노력하고 해시 테이블과 같은 크기로 매우 가능성 (즉 최대 값이다) (MD5는 SHA-1은 20 바이트, 16 바이트이며,. .hashCode()
입니다 int
- 4 바이트).
그래서 당신의 질문은 다음 단계에 관한 것입니다-일단 우리가 임의의 입력을 숫자로 매핑 할 수있는 해시 함수를 가지면 어떻게 특정 크기의 데이터 구조에 입력합니까? 다른 기능으로 "해시 함수"라고도합니다!
이러한 함수의 간단한 예는 모듈로입니다 . 모듈로를 사용하여 배열의 여러 인덱스를 특정 인덱스에 쉽게 매핑 할 수 있습니다. 이것은 "분할 방법"으로 CLRS에 도입되었습니다.
에서 분할 방법 해시 함수를 생성하는, 우리는 맵 키 중 하나로 나머지 슬롯을 취하여 로 나눈 값 . 즉, 해시 함수는케이미디엄케이미디엄
h ( k ) = k mod 입니다.미디엄
...
나누기 방법을 사용할 때 일반적으로 특정 값을 피합니다 . 예를 들어, 있으면되므로, 2의 거듭 제곱이어야한다 다음 단지 인 의 최하위 비트 .미디엄미디엄m = 2피h ( k )피케이
~ 알고리즘 소개, §11.3.1-CLRS
따라서 모듈로는 기본 데이터 구조에 안전하게 사용할 수있는 크기를 제한하기 때문에 훌륭한 해시 함수가 아닙니다. 다음 섹션에서는 모듈로를 사용하지만 " 의 값이 중요하지 않기 때문에"유리한 매우 복잡한 "곱셈법"을 소개합니다 . 그러나 "해시되는 데이터의 특성"에 대한 사전 지식과 함께 가장 잘 작동합니다.미디엄
Java HashMap
는 약한 .hashCode()
구현 을 설명하기 위해 사전 처리 단계를 수행하는 수정 된 버전의 나눗셈 방법을 사용하여 2의 거듭 제곱 배열을 사용할 수 있습니다. 당신은 .getEntry()
방법 에서 무슨 일이 일어나고 있는지 정확하게 볼 수 있습니다 (의견은 내 것입니다).
// hash() transforms key.hashCode() to protect against bad hash functions
int hash = (key == null) ? 0 : hash(key.hashCode());
// indexOf() converts the resulting hash to a value between 0 and table.length-1
for (Entry<K,V> e = table[indexFor(hash, table.length)];
...
Java 8은 재 작성 HashMap
이 더 빠르지 만 읽기가 조금 더 어려워졌습니다. 그러나 인덱스 조회에는 동일한 일반 원칙이 사용됩니다.