(충돌이 적은) 해시 테이블 조회가 실제로 O (1) 인 이유는 무엇입니까?


10

면책 조항 : 나는 이미 여기와 Stackoverflow에 비슷한 소리가 나는 질문이 있다는 것을 알고 있습니다. 그러나 그들은 모두 충돌에 관한 것입니다.

내 질문은 : 왜 충돌이 적은 조회 O(1)가 처음입니까?

이 해시 테이블이 있다고 가정 해 봅시다.

Hash  Content
-------------
ghdjg Data1
hgdzs Data2
eruit Data3
xcnvb Data4
mkwer Data5
rtzww Data6

이제 k해시 함수가 h(k)제공 하는 키를 찾고 h(k) = mkwer있습니다. 그러나 조회는 해시 mkwer가 위치 5에 있음을 어떻게 "알고" 있습니까? 왜 모든 키를 스크롤 O(n)하여 찾을 필요가 없습니까? 해시는 데이터를 이동할 수있는 능력을 잃어 버릴 수 있기 때문에 실제 하드웨어 주소가 될 수 없습니다. 그리고 내가 아는 한 해시 테이블은 해시별로 정렬되지 않습니다 (그렇더라도 검색에도 걸리지 않습니다 O(log n))?

해시를 아는 것이 테이블에서 올바른 장소를 찾는 데 어떻게 도움이됩니까?

답변:


24

해시 함수 과 같은 문자열을 반환 하지 않습니다mkwer . 배열에서 항목의 위치를 ​​직접 반환합니다. 예를 들어 해시 테이블에 10 개의 항목이 있으면 해시 함수는 0-9 범위의 정수를 반환합니다.


1
감사. :) 내 실수는 MD5 또는 SHA와 같은 해시 테이블 해시 함수를 생각하고있었습니다. 그러나 해시는 물론 내가 생각하지 않은 정수 위치 일 수 있습니다. 이제 무엇을 찾아야하는지 알았 으므로
Foo Bar

13
@FooBar : MD5와 SHA는 입력에서 단일 숫자를 계산하기도합니다. 16 진 형식으로 해시에 대해 말하는 것이 일반적입니다. 메모리 주소는 거의 십진수로 간주되지 않습니다.
nperson325681

4
또한 MD5 등은 너무 길어서 배열 인덱스로 직접 사용할 수 없습니다. 하위 n 비트 와 같이 해시의 일부를 사용할 수 있습니다 .
chirlu

6

해시 함수는 주어진 문자열에서 배열 위치를 계산합니다 . 이것이 완벽한 해시라면 충돌이 없음을 의미하며, 아마도 배열은 요소 수보다 적어도 두 배 더 큽니다.

예를 들어 메카니즘을 설명하기 위해 문자에 매우 해시를 줄 것입니다.
0) 1) 문자열의 각 문자에 대해 ASCII 값을 취하고 소문자 인 경우 'a'를 빼고 대문자 인 경우 'A'를 빼고 x에 값을 추가하십시오. 2) 결과 수, 예를 들어 15는 배열의 인덱스입니다. x = x m o d 52엑스=0;
엑스=엑스미디엄영형52

이 매우 간단한 해시 (제한되고 충돌하기 쉬운)는 해싱 메커니즘에서 다른 해시와 다르며 주어진 입력을 고려하지 않습니다. 더 고급 체계에서 해시는 요소 수에 따라 더 큰 수입니다. 충돌이 발생하지 않도록 모든 입력에 대해 완벽한 해시가 생성됩니다.

이것은 문자열에서 해시를 계산하는 것이 얼마나 복잡한 함수를 계산 하느냐에 달려 있지만 요소 수에 의존하지 않기 때문에 입니다.영형(1)

완벽한 해시의 경우 요소가 추가되면 가 다시 계산되고 배열 부하가 클 때 충돌이 발생하는 간단한 경우는 배열 크기가 증가하고 함수는 더 큰 출력 모듈러스를 취하며 요소는 새로운 위치로 이동합니다.h(케이)

배열은 연속적인 메모리 조각이므로 요소 를 얻으려면 첫 번째 요소의 주소 (배열 시작)를 가져온 다음이 주소에 추가하여 명시 적 메모리 셀을 갖습니다.n ( s i z e o f e l e m e n t )h(에스나는이자형영형에프이자형이자형미디엄이자형)


1
그리고 조회 는 테이블에서 해시가 어디에 있는지 어떻게 알 수 있습니까? 주문도 하드웨어 주소도 아닙니다.
Foo Bar

예를 들어 "xcnvb", 같은 문자열을 제공 하므로 계산 된 해시는 배열의 인덱스를 제공하고 "xcnvb"는 조회 할 요소이며 8은 테이블의 인덱스입니다. 주문은 끄덕이며 해시는 장소를 검색 요소로 반환합니다. 이 요소는 동일한 기능으로 거기에 놓였습니다. 하드웨어는 여기서 할 일이 없습니다. 배열, 해시 함수 및 계산 해시를 제공하여 검색과 동일하게 배열의 인덱스를 가져옵니다. 배열이 정렬되지 않았으며 가득 찼습니다. h("엑스V")=8
Evil

그러나 모든 색인이 채워지는 것은 아닙니다. 데이터로 채워진 해시 1, 4, 8, 90 및 223이있는 경우 조회에서 올바른 위치를 찾는 방법은 무엇입니까? 이 경우 대부분의 다른 인덱스가 존재하지 않기 때문에 인덱스 "90"은 위치 4에 있습니다. 그리고 빈 해시 테이블은 가능한 모든 위치를 갖는 무한 크기가 아닙니다!?
Foo Bar

예, 배열은 512 요소 길이, 해시 함수에 9 비트가 사용되며 4 요소 만 있다고 가정합니다. 예를 들어 인덱스 90은 배열에서 위치 90을 갖습니다. 거의 모든 셀이 비어 있습니다. 배열이 경우 색인을 생성합니다. = "xcnvb"에 대한 데이터HH(h("엑스V"))=H[90]
Evil

해시 함수는 배열에 인덱스를 반환하지 않습니다. 대신, 배열에 매핑 될 수있는 예측 가능한 숫자를 반환합니다. 일반적으로 다른 피연산자로서 해시 테이블 버킷 수와 함께 모듈러스 연산자를 사용하여 수행됩니다 .
Christopher Schultz

3

David Richerby의 답변을 확장하기 위해 " 해시 함수 " 라는 용어 는 약간 오버로드되었습니다. 종종 해시 함수에 대해 이야기 할 때 MD5, SHA-1 또는 Java의 .hashCode()메소드 와 같은 것을 생각하며 일부 입력을 단일 숫자로 바꿉니다. 그러나이 숫자의 도메인은 당신이 데이터를 저장하는 데 노력하고 해시 테이블과 같은 크기로 매우 가능성 (즉 최대 값이다) (MD5는 SHA-1은 20 바이트, 16 바이트이며,. .hashCode()입니다 int- 4 바이트).

그래서 당신의 질문은 다음 단계에 관한 것입니다-일단 우리가 임의의 입력을 숫자로 매핑 할 수있는 해시 함수를 가지면 어떻게 특정 크기의 데이터 구조에 입력합니까? 다른 기능으로 "해시 함수"라고도합니다!

이러한 함수의 간단한 예는 모듈로입니다 . 모듈로를 사용하여 배열의 여러 인덱스를 특정 인덱스에 쉽게 매핑 할 수 있습니다. 이것은 "분할 방법"으로 CLRS에 도입되었습니다.

에서 분할 방법 해시 함수를 생성하는, 우리는 맵 키 중 하나로 나머지 슬롯을 취하여 로 나눈 값 . 즉, 해시 함수는케이미디엄케이미디엄

h(케이)=케이 mod 입니다.미디엄

...

나누기 방법을 사용할 때 일반적으로 특정 값을 피합니다 . 예를 들어, 있으면되므로, 2의 거듭 제곱이어야한다 다음 단지 인 의 최하위 비트 .미디엄미디엄미디엄=2h(케이)케이

~ 알고리즘 소개, §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이 더 빠르지 만 읽기가 조금 더 어려워졌습니다. 그러나 인덱스 조회에는 동일한 일반 원칙이 사용됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.