해시 테이블이 실제로 O (1) 일 수 있습니까?


114

해시 테이블이 O (1)을 달성 할 수 있다는 것은 상식 인 것처럼 보이지만 그것은 결코 이해가되지 않습니다. 누군가 그것을 설명해 주시겠습니까? 떠오르는 두 가지 상황은 다음과 같습니다.

A. 값은 해시 테이블의 크기보다 작은 int입니다. 따라서 값은 자체 해시이므로 해시 테이블이 없습니다. 그러나 만약 있다면 그것은 O (1)이고 여전히 비효율적입니다.

B. 값의 해시를 계산해야합니다. 이 상황에서 조회되는 데이터 크기의 순서는 O (n)입니다. O (n) 작업을 수행 한 후 조회는 O (1) 일 수 있지만 여전히 내 눈에는 O (n)으로 나옵니다.

그리고 완벽한 해시 나 큰 해시 테이블이 없으면 버킷 당 여러 항목이있을 수 있습니다. 그래서 어쨌든 어느 시점에서 작은 선형 검색으로 발전합니다.

나는 해시 테이블이 굉장하다고 생각하지만 이론적이라고 가정하지 않는 한 O (1) 지정을 얻지 못합니다.

해시 테이블에 대한 Wikipedia의 기사는 일관되게 일정한 조회 시간을 참조하고 해시 함수의 비용을 완전히 무시합니다. 정말 공정한 조치입니까?


편집 : 내가 배운 내용을 요약하면 다음과 같습니다.

  • 해시 함수가 키의 모든 정보를 사용하는 데 필요하지 않고 일정한 시간이 될 수 있고 충분히 큰 테이블이 충돌을 거의 일정한 시간으로 낮출 수 있기 때문에 기술적으로 사실입니다.

  • 실제로는 시간이 지남에 따라 충돌을 최소화하기 위해 해시 함수와 테이블 크기가 선택되는 한 제대로 작동하기 때문에 사실입니다. 이는 종종 일정한 시간 해시 함수를 사용하지 않음을 의미합니다.


31
상각 된 O (1)이지 O (1)이 아닙니다.
kennytm 2010

O ()는 많은 수의 작업에 대한 제한입니다. '평균'에서는 충돌이 많이 발생하지 않습니다. 개별 작업에 충돌이 없을 필요는 없습니다.
Martin Beckett

문자열 구현에 따라 문자열은 해시 된 값을 포함 할 수 있으므로 이는 일정합니다. 요점은 해시 조회 복잡성과 관련이 없다는 것입니다.
Rich Remer

@kennytm 물론, 입력을 해시 한 후 조회 는 O (1)로 상각됩니다. 그러나 해시를 계산하는 데 드는 비용은 정말 무시할 만합니까? 문자열 (문자 배열)을 해싱한다고 가정합니다. 해시를 생성하려면 각 문자가 반복되므로 문자열 해싱은 O (N)이며 여기서 N은 문자열의 길이입니다. 이것이 C #에 대해 문서화 된 hashCode()방법이며 Java의 메서드가 String. grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
spaaarky21

1
@ spaaarky21 당신이 말하는 O (N)의 N은 해시 테이블의 크기 인 n과는 다른 문자열의 길이입니다. Mark Byer의 대답은 이미 이것을 다루었습니다.
kennytm

답변:


65

여기에 두 개의 변수, m과 n이 있습니다. 여기서 m은 입력의 길이이고 n은 해시의 항목 수입니다.

O (1) 조회 성능 주장은 최소한 두 가지 가정을합니다.

  • 객체는 O (1) 시간에 동등성을 비교할 수 있습니다.
  • 해시 충돌이 거의 없습니다.

객체가 가변 크기이고 동등성 검사에서 모든 비트를 확인해야하는 경우 성능은 O (m)가됩니다. 그러나 해시 함수는 O (m) 일 필요는 없습니다. O (1) 일 수 있습니다. 암호화 해시와 달리 사전에서 사용하는 해시 함수는 해시를 계산하기 위해 입력의 모든 비트를 볼 필요가 없습니다. 구현은 고정 된 수의 비트 만 볼 수 있습니다.

항목 수가 충분히 많은 경우 항목 수가 가능한 해시 수보다 커지고 충돌이 발생하여 성능이 O (1) 이상으로 상승합니다. 예를 들어 간단한 연결 목록 순회 (또는 O (n) * m) 두 가정이 모두 거짓 인 경우).

실제로 O (1) 주장은 기술적으로 거짓이지만 많은 실제 상황, 특히 위의 가정이 적용되는 상황에서 거의 참입니다.


4
위와 마찬가지로 해시를 한 번 계산 한 Java Strings와 같이 변경 불가능한 객체를 키로 사용하는 경우이를 기억할 수 있으며 다시 계산할 필요가 없습니다. 반면에 올바른 버킷을 찾으면 두 키가 같은지 확인하기 위해 일반적으로 해시에 의존 할 수 없으므로 문자열의 경우 O (m) 순회를 수행하여 동일한 지 확인해야합니다.
JeremyP 2010

1
@JeremyP : O (m) 평등 비교의 좋은 점입니다. 나는 그것을 놓쳤다-업데이트 된 게시물. 감사!
Mark Byers

2
O(1)주장은 사실 당신이있는 거 해시 경우 int다른 s 또는 뭔가 그 기계 단어에 맞는. 이것이 대부분의 해싱 이론이 가정하는 것입니다.
Thomas Ahle 2014 년

나는 당신의 Mark에 대한 설명을 좋아합니다. meshfields.de/hash-tables의
Steve K

3
에서 "m는 입력의 길이입니다" - 입력 이 삽입되는 모든 키 및 값을 의미 할 수 있습니다, 그러나 당신이 평균 (적어도 이미 주제를 이해하는 사람들에게) 나중에 분명해진다 - 지나치게 모호 키를 . 명확성을 위해 대답에 "키"를 사용하는 것이 좋습니다. BTW-구체적인 예-Visual C ++ std::hash의 텍스트 키는 텍스트를 따라 균등하게 배치 된 10 개의 문자를 해시 값으로 결합하므로 텍스트 길이에 관계없이 O (1)입니다 (하지만 GCC보다 충돌이 더 많이 발생합니다!). 별도로 O (1)의 주장은 mn 보다 훨씬 작다 는 또 다른 가정 (일반적으로 올바르게)을 가지고 있습니다.
Tony Delroy

22

해시를 계산해야하므로 조회되는 데이터 크기의 순서는 O (n)입니다. O (n) 작업을 수행 한 후 조회는 O (1) 일 수 있지만 여전히 내 눈에는 O (n)으로 나옵니다.

뭐? 단일 요소를 해시하려면 일정한 시간이 걸립니다. 다른 이유는 무엇입니까? n요소를 삽입하는 경우 예, n해시 를 계산 해야하며 선형 시간이 걸립니다. . 이미 해시 테이블에있는 모든 항목의 해시를 다시 계산하지 않습니다.

그리고 완벽한 해시 나 큰 해시 테이블이없는 한 버킷 당 여러 항목이있을 수 있으므로 어쨌든 어느 시점에서 작은 선형 검색으로 전환됩니다.

반드시 그런 것은 아닙니다. 버킷은 반드시 목록 또는 배열 일 필요는 없으며 균형 잡힌 BST와 같은 모든 컨테이너 유형일 수 있습니다. 그것은 O(log n)최악의 경우를 의미 합니다. 그러나 이것이 하나의 버킷에 너무 많은 요소를 넣지 않도록 좋은 해싱 함수를 선택하는 것이 중요한 이유입니다. KennyTM가 지적했듯이, O(1)가끔 양동이를 파헤쳐 야하는 경우에도 평균적으로 여전히 시간을 얻을 수 있습니다.

해시 테이블의 트레이드 오프는 물론 공간 복잡성입니다. 당신은 시간을 위해 공간을 거래하고 있는데, 이는 컴퓨팅 과학의 일반적인 경우 인 것 같습니다.


다른 주석 중 하나에서 문자열을 키로 사용한다고 언급했습니다. 여러 문자로 구성되어 있기 때문에 문자열의 해시를 계산하는 데 걸리는 시간에 대해 걱정하십니까? 다른 사람이 다시 지적했듯이 해시를 계산하기 위해 모든 문자를 볼 필요는 없지만 그렇게하면 더 나은 해시를 생성 할 수 있습니다. 이 경우 m키 에 평균 문자가 있고 모든 문자를 사용하여 해시를 계산하면 옳다고 생각합니다 O(m). 그렇다면 m >> n문제가있을 수 있습니다. 이 경우 BST를 사용하는 것이 더 나을 것입니다. 또는 더 저렴한 해싱 기능을 선택하십시오.


해시 테이블은 BST를 사용하지 않습니다. BST에는 해시 값이 필요하지 않습니다. 하지만 맵과 세트는 BST로 구현할 수 있습니다.
Nick Dandoulakis 2010

3
@ 닉 : 어? 아니요 ... BST에는 해시 값이 필요하지 않습니다 ... 그게 요점입니다. 이 시점에서 이미 충돌 (동일한 해시 ... 또는 최소한 동일한 버킷)이 있다고 가정하고 있으므로 올바른 요소, 즉 실제 값을 찾기 위해 다른 것을 살펴 봐야합니다.
mpen 2010

오, 당신의 요점이 보입니다. 그러나 BST와 해시를 혼합하는 것이 문제의 가치가 있는지 확실하지 않습니다. 왜 BST를 사용하지 않습니까?
Nick Dandoulakis 2010

2
나는 단지 충돌 을 위해 그것을 제거 할 있다고 말하는 것입니다 O(n). 당신이하면 된다 충돌을 많이 기대, 그때는 아마 더 나은 첫 번째 장소에서 BST와 함께가는 떨어져, 맞아.
mpen 2010

1
@ spaaarky21 맞지만 N이 경우 문자열의 길이입니다. 들어가야 할 '버킷'을 결정하기 위해 하나의 문자열 만 해시 하면됩니다. 해시 맵의 길이에 따라 늘어나지 않습니다.
mpen

5

해시는 고정 된 크기입니다. 적절한 해시 버킷을 찾는 것은 고정 비용 작업입니다. 이것은 O (1)임을 의미합니다.

해시 계산은 특별히 비용이 많이 드는 작업 일 필요는 없습니다. 여기서는 암호화 해시 함수에 대해 이야기하지 않습니다. 그러나 그것은 의해입니다. 해시 함수 계산 자체는 요소 수 n 에 의존하지 않습니다 . 요소의 데이터 크기에 따라 달라질 수 있지만 이것은 n이 나타내는 것이 아닙니다 . 따라서 해시 계산은 n에 의존하지 않고 O (1)이기도합니다.


3
해시 버킷을 찾는 것은 O (1)입니다. 그러나 올바른 키를 찾는 것은 O (n) 절차이며, 여기서 n은 해시 충돌 수에 따라 다릅니다.
Nick Dandoulakis 2010

1
3 단계 중 해시를 계산하고 버킷을 찾고 버킷을 검색하면 중간 단계가 일정할까요? 버킷 검색은 일반적으로 일정합니다. 해시를 계산하는 것은 일반적으로 버킷을 찾는 다른 방법보다 몇 배 더 저렴합니다. 그러나 그것이 정말로 일정한 시간에 합산됩니까? 순진한 하위 문자열 검색에서 두 길이에 대해 O (n * m)라고 말하면 키의 길이가 여기서 무시되는 이유는 무엇입니까?
2010

고정 길이 키를 찾는 것은 목록이 지원되는 경우에만 O (n)이며 균형 잡힌 트리 지원 해시 테이블은 O (log (n))
jk가됩니다.

@Jk 좋은 해시 함수의 경우 최악의 경우는 항상입니다 logn. stackoverflow.com/questions/4553624/hashmap-get-put-complexity/…
Thomas Ahle

최악의 경우에 복잡성은 충돌의 경우 (n)이 O를 할 것이다
Saurabh 찬드라 파텔

3

해싱은 테이블에 일정한 수의 키만 있고 다른 가정이 이루어진 경우에만 O (1)입니다. 그러나 그러한 경우에는 이점이 있습니다.

키에 n 비트 표현이있는 경우 해시 함수는 이러한 비트 중 1, 2, ... n을 사용할 수 있습니다. 1 비트를 사용하는 해시 함수를 생각해보세요. 평가는 확실히 O (1)입니다. 그러나 키 공간을 2로만 분할합니다. 따라서 동일한 빈에 2 ^ (n-1) 키를 매핑합니다. BST 검색을 사용하면 거의 가득 찬 경우 특정 키를 찾는 데 최대 n-1 단계가 걸립니다.

이것을 확장하여 해시 함수가 K 비트를 사용하는 경우 bin 크기가 2 ^ (nk)임을 확인할 수 있습니다.

따라서 K- 비트 해시 함수 ==> 2 ^ K 개 이하의 유효 빈 ==> 최대 2 ^ (nK) 개의 빈당 n- 비트 키 ==> (nK) 단계 (BST)로 충돌을 해결합니다. 실제로 대부분의 해시 함수는 "효과적이지"않으며 2 ^ k 빈을 생성하기 위해 K 비트 이상을 필요로 / 사용합니다. 그래서 이것조차도 낙관적입니다.

이런 식으로 볼 수 있습니다. 최악의 경우 n 비트의 키 쌍을 고유하게 구별하려면 ~ n 단계가 필요합니다. 해시 테이블이든 아니든이 정보 이론 한계를 피할 수있는 방법은 없습니다.

그러나 이것은 해시 테이블을 사용하는 방법 /시기가 아닙니다!

복잡도 분석에서는 n 비트 키의 경우 테이블에 O (2 ^ n) 키가있을 수 있다고 가정합니다 (예 : 가능한 모든 키의 1/4). 그러나 대부분은 아니지만 해시 테이블을 사용하는 경우 테이블에는 n 비트 키의 상수 만 있습니다. 테이블에 일정한 수의 키만 원하는 경우 (예 : C가 최대 수라고 말하면) O (C) 빈의 해시 테이블을 형성하여 예상되는 상수 충돌을 보장 할 수 있습니다 (좋은 해시 함수 사용). 및 키에있는 n 비트의 ~ logC를 사용하는 해시 함수. 그러면 모든 쿼리는 O (logC) = O (1)입니다. 이것이 사람들이 "해시 테이블 액세스가 O (1)"라고 주장하는 방법입니다.

여기에는 몇 가지 문제가 있습니다. 첫째, 모든 비트가 필요하지 않다는 것은 결제 트릭 일뿐입니다. 먼저 해시 함수에 키 값을 전달할 수 없습니다. 그 이유는 O (n) 인 메모리에서 n 비트를 이동하기 때문입니다. 따라서 예를 들어 참조 전달을 수행해야합니다. 그러나 여전히 O (n) 연산이었던 어딘가에 저장해야합니다. 당신은 단지 그것을 해싱에 청구하지 않습니다; 전체적인 계산 작업은 이것을 피할 수 없습니다. 둘째, 해싱을 수행하고 빈을 찾고 둘 이상의 키를 찾았습니다. 비용은 해결 방법에 따라 다릅니다. 비교 기반 (BST 또는 목록)을 수행하면 O (n) 작업이 수행됩니다 (리콜 키는 n 비트 임). 두 번째 해시를 수행하면 두 번째 해시가 충돌하면 동일한 문제가 발생합니다.

이 경우 BST와 같은 대안을 고려하십시오. C 키가 있으므로 균형 잡힌 BST는 깊이가 O (logC)이므로 검색에는 O (logC) 단계가 필요합니다. 그러나이 경우의 비교는 O (n) 연산이 될 것입니다. 따라서이 경우에는 해싱이 더 나은 선택 인 것으로 보입니다.


1

요약 : 해시 테이블 O(1)은 범용 해시 함수 제품군에서 임의로 균일하게 해시 함수를 선택하는 경우 예상되는 최악의 경우 시간을 보장 합니다. 예상되는 최악의 경우는 평균 사례와 동일하지 않습니다.

면책 조항 : 저는 해시 테이블이라는 것을 공식적으로 증명하지 않습니다 . O(1)이는 coursera [ 1 ] 의이 비디오를 봤기 때문 입니다. 또한 해시 테이블 의 상각 된 측면에 대해서도 논의하지 않습니다 . 이는 해싱 및 충돌에 대한 논의와 직교합니다.

나는 다른 답변과 댓글 에서이 주제에 대해 놀랍도록 많은 혼란을 겪고 있으며이 긴 답변에서 일부를 수정하려고 노력할 것입니다.

최악의 경우에 대한 추론

다양한 유형의 최악의 경우 분석이 있습니다. 지금까지 대부분의 답변이 만든 분석 최악의 경우가 아니라 평균적인 경우입니다 [ 2 ]. 평균 사례 분석이 더 실용적인 경향이 있습니다. 알고리즘에 최악의 경우 하나의 입력이 있지만 실제로는 다른 모든 입력에 대해 잘 작동합니다. 결론은 런타임 이 실행중인 데이터 세트에 따라 달라진다 는 것 입니다.

get해시 테이블 메서드의 다음 의사 코드를 고려하십시오 . 여기서는 연결을 통해 충돌을 처리한다고 가정하므로 테이블의 각 항목은 연결된 (key,value)쌍 목록입니다 . 우리는 또한 버킷의 수를 가정 m고정되어 있지만 O(n), 여기서 n입력 요소의 수입니다.

function get(a: Table with m buckets, k: Key being looked up)
  bucket <- compute hash(k) modulo m
  for each (key,value) in a[bucket]
    return value if k == key
  return not_found

다른 답변에서 지적했듯이 이것은 평균 O(1)및 최악의 경우로 실행됩니다 O(n). 여기서 도전으로 증명의 작은 스케치를 만들 수 있습니다. 과제는 다음과 같습니다.

(1) 해시 테이블 알고리즘을 적에게 제공합니다.

(2) 적은 원하는만큼 공부하고 준비 할 수 있습니다.

(3) 마지막으로 공격자는 n테이블에 삽입 할 크기 를 입력 합니다.

문제는 적의 입력에 대한 해시 테이블이 얼마나 빠르 냐는 것입니다.

(1) 단계에서 공격자는 해시 함수를 알고 있습니다. 단계 (2) 동안 공격자는 예를 들어 여러 요소의 해시를 무작위로 계산하여 n동일한 요소 의 목록을 만들 수 있습니다 hash modulo m. 그리고 (3)에서 그들은 당신에게 그 목록을 줄 수 있습니다. 그러나 모든 n요소가 동일한 버킷으로 해시되므로 알고리즘이 O(n)해당 버킷의 연결 목록을 순회하는 데 시간 이 걸립니다 . 우리가 챌린지를 몇 번 재 시도해도 적은 항상 이기고 알고리즘이 얼마나 나쁜지 최악의 경우 O(n)입니다.

해싱은 어떻게 O (1)입니까?

이전 도전에서 우리를 좌절시킨 것은 적들이 우리의 해시 함수를 아주 잘 알고 있었고 그 지식을 사용하여 가능한 최악의 입력을 만들 수 있다는 것입니다. 항상 하나의 고정 된 해시 함수를 사용하는 대신 H알고리즘이 런타임에 임의로 선택할 수있는 해시 함수 집합이 실제로 있다면 어떨까요? 궁금한 점이 있으면 해시 함수H범용 제품군 [ 3 ]이라고합니다. 좋습니다. 여기에 임의성 을 추가해 보겠습니다 .

먼저 우리의 해시 테이블도 씨앗을 포함한다고 가정 r하고, r시공시 임의의 숫자에 할당됩니다. 한 번 할당하면 해시 테이블 인스턴스에 대해 수정됩니다. 이제 의사 코드를 다시 살펴 보겠습니다.

function get(a: Table with m buckets and seed r, k: Key being looked up)
  rHash <- H[r]
  bucket <- compute rHash(k) modulo m
  for each (key,value) in a[bucket]
    return value if k == key
  return not_found

도전을 한 번 더 시도하면 (1) 단계에서 공격자는 우리가 가지고있는 모든 해시 함수를 알 수 H있지만 이제 우리가 사용하는 특정 해시 함수는에 의존합니다 r. 의 값은 r우리 구조에 비공개이며, 공격자는이를 런타임에 검사하거나 미리 예측할 수 없으므로 항상 우리에게 나쁜 목록을 만들 수 없습니다. 의 단계에서 (2) 대적 하나 개의 기능을 선택한다고 가정하자 hash에서 H무작위로, 그는 다음 목록으로 만들어줍니다 n에서 충돌 hash modulo m, 그리고 보냅니다 런타임에 있음을 손가락을 교차 단계 (3)에 대해 H[r]동일합니다 hash그들이 선택합니다.

이것은 적들에게 심각한 내기이며 그가 만든 목록은.에서 충돌 hash하지만의 다른 해시 함수 아래에서 무작위 입력이 될 것입니다 H. 그가이 내기에서 이기면 우리의 실행 시간은 O(n)이전과 같이 최악의 경우가 될 것이지만 그가지면 평균 O(1)시간 이 걸리는 임의의 입력을 받게 됩니다. 그리고 실제로 대부분의 적이지는 경우, 그는 모든 |H|도전에서 단 한 번만 이기며 우리는 |H|매우 크게 만들 수 있습니다.

이 결과를 적이 항상 도전에서이긴 이전 알고리즘과 대조하십시오. 여기에 조금 Handwaving하지만 이후 대부분의 시간 대적이 실패하고 이것이 사탄이 시도 할 수있는 모든 전략에 대한 사실, 최악의 경우가 있지만 것을 다음 O(n)예상되는 최악의 경우는 사실이다 O(1).


다시 말하지만 이것은 공식적인 증거가 아닙니다. 이 예상 최악의 경우 분석에서 얻을 수있는 보장은 런타임이 이제 특정 입력과 독립적이라는 것 입니다. 이것은 우리가 동기를 부여한 적이 나쁜 입력을 쉽게 만들 수 있음을 보여준 평균 사례 분석과는 달리 진정한 무작위 보장입니다.


0

최악의 경우 O (1)를 얻을 수있는 두 가지 설정이 있습니다 .

  1. 설정이 정적 인 경우 FKS 해싱은 최악의 경우 O (1) 보장을 제공합니다. 그러나 귀하가 지적했듯이 귀하의 설정은 고정되어 있지 않습니다.
  2. Cuckoo 해싱을 사용하는 경우 쿼리 및 삭제는 최악의 경우 O (1) 이지만 삽입은 O (1) 만 예상됩니다. Cuckoo 해싱은 총 삽입 수에 상한이 있고 테이블 크기를 약 25 % 더 크게 설정하는 경우 매우 잘 작동합니다.

여기 에서 복사


0

여기서 논의한 바에 따르면 X가 (테이블의 요소 수 / 빈 수)의 상한선이면 빈 조회의 효율적인 구현을 가정하면 더 나은 대답은 O (log (X))입니다.


0

A. 값은 해시 테이블의 크기보다 작은 int입니다. 따라서 값은 자체 해시이므로 해시 테이블이 없습니다. 그러나 만약 있다면 그것은 O (1)이고 여전히 비효율적입니다.

이것은 키를 별개의 버킷에 사소하게 매핑 할 수있는 경우이므로 배열이 해시 테이블보다 데이터 구조의 더 나은 선택으로 보입니다. 그럼에도 불구하고 비 효율성은 테이블 크기에 따라 증가하지 않습니다.

(프로그램이 발전함에 따라 int가 테이블 크기보다 작게 유지되는 것을 신뢰하지 않기 때문에 해시 테이블을 계속 사용할 수 있습니다. 해당 관계가 유지되지 않을 때 코드를 잠재적으로 재사용 가능하게 만들고 싶거나 코드를 읽고 유지하는 사람들이 관계를 이해하고 유지하는 데 정신적 노력을 낭비하기를 원합니다.)

B. 값의 해시를 계산해야합니다. 이 상황에서 조회되는 데이터 크기의 순서는 O (n)입니다. O (n) 작업을 수행 한 후 조회는 O (1) 일 수 있지만 여전히 내 눈에는 O (n)으로 나옵니다.

키 크기 (예 : 바이트)와 해시 테이블에 저장되는 키 수의 크기를 구분해야합니다. 해시 테이블이 O (1) 작업을 제공한다는 주장 은 키 수가 수백에서 수천에서 수백만에서 수십억으로 증가함에 따라 작업 (삽입 / 지우기 / 찾기)이 더 이상 느려지지 않는 경향이 있음을 의미합니다 (적어도 모든 데이터가 똑같이 빠른 스토리지에서 액세스 / 업데이트됩니다. 즉, RAM 또는 디스크-캐시 효과가 나타날 수 있지만 최악의 경우 캐시 미스의 비용조차도 최적의 히트의 일정한 배수 인 경향이 있습니다).

전화 번호부를 생각해보십시오. 꽤 긴 이름이있을 수 있지만 책에 100 개의 이름이 있든 천만 개이든 상관없이 평균 이름 길이는 매우 일관 적이며 역사상 최악의 경우입니다.

누구나 사용한 가장 긴 이름에 대한 기네스 세계 기록은 Adolph Blaine Charles David Earl Frederick Gerald Hubert Irvin John Kenneth Lloyd Martin Nero Oliver Paul Quincy Randolph Sherman Thomas Uncas Victor William Xerxes Yancy Wolfeschlegelsteinhausenbergerdorff, Senior

... wc나 215 개 문자의 그 이야기 - 아니에요 하드 키 길이에 상한선하지만, 우리가있는가에 대해 걱정할 필요가 없습니다 대규모 더.

이는 대부분의 실제 해시 테이블에 적용됩니다. 평균 키 길이는 사용중인 키 수에 따라 증가하지 않습니다. 예외가 있습니다. 예를 들어 키 생성 루틴은 증가하는 정수를 포함하는 문자열을 반환 할 수 있지만 키 수를 몇 배로 늘릴 때마다 키 길이를 1 자만 늘립니다. 이는 중요하지 않습니다.

고정 된 크기의 키 데이터에서 해시를 생성하는 것도 가능합니다. 예를 들어, Microsoft의 Visual C ++ std::hash<std::string>는 문자열을 따라 균등 한 간격으로 10 바이트 만 통합하는 해시를 생성 하는 표준 라이브러리 구현 과 함께 제공되므로 문자열이 다른 인덱스에서만 변경되면 충돌이 발생합니다 (실제로는 비 O (1) 동작). 충돌 후 검색 측면에서) 그러나 해시를 생성하는 시간에는 하드 상한선이 있습니다.

그리고 완벽한 해시 나 큰 해시 테이블이 없으면 버킷 당 여러 항목이있을 수 있습니다. 그래서 어쨌든 어느 시점에서 작은 선형 검색으로 발전합니다.

일반적으로 사실이지만 해시 테이블의 멋진 점은 "작은 선형 검색"중에 방문한 키의 수가 충돌 에 대한 별도의 체인 접근 방식의 경우 해시 테이블 부하 계수 (버킷에 대한 키의 비율)의 함수라는 것입니다 .

예를 들어로드 팩터가 1.0이면 키 수에 관계없이 선형 검색 길이에 평균 ~ 1.58이 있습니다 ( 여기 내 답변 참조 ). 들어 폐쇄 해싱 은 좀 더 복잡하지만, 부하 계수가 너무 높지 않을 때 훨씬 더합니다.

해시 함수가 키의 모든 정보를 사용하는 데 필요하지 않고 일정한 시간이 될 수 있고 충분히 큰 테이블이 충돌을 거의 일정한 시간으로 낮출 수 있기 때문에 기술적으로 사실입니다.

이런 종류의 요점을 놓친다. 모든 종류의 연관 데이터 구조는 궁극적으로 키의 모든 부분에 걸쳐 연산을 수행해야합니다 (때로는 키의 일부에서만 부 등성이 결정될 수 있지만 일반적으로 동일성은 모든 비트를 고려해야 함). 최소한 키를 한 번 해시하고 해시 값을 저장할 수 있으며, 충분히 강력한 해시 기능 (예 : 64 비트 MD5)을 사용하는 경우 두 키가 동일한 값 (회사)으로 해싱 될 가능성도 거의 무시할 수 있습니다. 저는 분산 데이터베이스에 대해 정확히 그렇게했습니다. 해시 생성 시간은 WAN 전체 네트워크 전송에 비해 여전히 미미했습니다.) 따라서 키를 처리하는 데 드는 비용에 대해 집착하는 것은별로 중요하지 않습니다. 이는 데이터 구조에 관계없이 키를 저장하는 데 내재되어 있으며 위에서 말했듯이 그렇지 않습니다.

충돌을 일으키는 충분히 큰 해시 테이블에 관해서도 요점을 놓치고 있습니다. 별도의 체인의 경우 주어진 하중 계수에서 평균 충돌 체인 길이가 일정합니다. 하중 계수가 더 높고 그 관계가 비선형 일 때 더 높아집니다. SO 사용자 Hans는 내 대답에 대해 다음 과 같이 언급 했습니다.

비어 있지 않은 버킷에 대해 조정 된 평균 버킷 길이가 더 나은 효율성 척도입니다. a / (1-e ^ {-a}) [여기서 a는 부하율, e는 2.71828 ...]

따라서로드 요소 만으로도 삽입 / 지우기 / 찾기 작업 중에 검색해야하는 충돌 키의 평균 수를 결정합니다. 별도의 체인의 경우 부하 계수가 낮을 때 일정하게 접근하는 것이 아니라 항상 일정합니다. 클레임에 약간의 타당성이 있지만 공개 주소 지정의 경우 일부 충돌 요소가 대체 버킷으로 리디렉션되고 다른 키에 대한 작업을 방해 할 수 있으므로 더 높은 부하 계수 (특히> .8 또는 .9)에서 충돌 체인 길이가 훨씬 더 악화됩니다.

실제로는 시간이 지남에 따라 충돌을 최소화하기 위해 해시 함수와 테이블 크기가 선택되는 한 제대로 작동하기 때문에 사실입니다. 이는 종종 일정한 시간 해시 함수를 사용하지 않음을 의미합니다.

글쎄요, 테이블 크기는 클로즈 해싱 또는 개별 체인을 선택할 때 정상적인로드 팩터를 가져야하지만 해시 함수가 약간 약하고 키가 매우 무작위가 아닌 경우에도 소수의 버킷을 사용하면 충돌도 마찬가지입니다 ( hash-value % table-size그런 다음 해시 값에서 상위 비트 또는 두 개에 대한 변경 사항 만 해시 테이블의 다른 부분에 의사 무작위로 분산 된 버킷으로 해결되도록 래핑됩니다).

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