[java] Java 해시 맵이 실제로 O (1)입니까?

SO re Java 해시 맵 및 O(1)조회 시간 에 대한 흥미로운 주장을 보았습니다 . 누군가 왜 이것이 그렇게 설명 할 수 있습니까? 이러한 해시 맵이 내가 구입 한 해시 알고리즘과 크게 다르지 않으면 충돌이 포함 된 데이터 세트가 항상 존재해야합니다.

어떤 경우에는 조회가 O(n)아닌 것 O(1)입니다.

사람은인지 설명 할 수 있다 O (1)와, 그렇다면, 그들이이 어떻게 달성?



답변

HashMap의 특별한 특징은 균형 잡힌 나무와 달리 그 행동이 확률 적이라는 것입니다. 이러한 경우 최악의 상황이 발생할 가능성의 관점에서 복잡성에 대해 이야기하는 것이 가장 도움이됩니다. 해시 맵의 경우, 물론 맵의 전체 크기와 관련하여 충돌이 발생한 경우입니다. 충돌은 추정하기 매우 쉽습니다.

p 충돌 = n / 용량

따라서 요소 수가 적은 해시 맵은 적어도 하나의 충돌이 발생할 가능성이 큽니다. Big O 표기법을 사용하면 더욱 매력적인 작업을 수행 할 수 있습니다. 임의의 고정 상수 k에 대해 관찰하십시오.

O (n) = O (k * n)

이 기능을 사용하여 해시 맵의 성능을 향상시킬 수 있습니다. 대신 최대 2 번의 충돌 가능성을 생각할 수 있습니다.

p 충돌 x 2 = (n / 용량) 2

이것은 훨씬 낮습니다. 한 번의 추가 충돌 처리 비용은 Big O 성능과 관련이 없으므로 알고리즘을 실제로 변경하지 않고도 성능을 향상시킬 수있는 방법을 찾았습니다! 우리는 이것을 generalzie 할 수 있습니다

p 충돌 xk = (n / 용량) k

그리고 이제 우리는 임의의 수의 충돌을 무시하고 우리가 설명하는 것보다 더 많은 충돌이 거의 없을 가능성이 있습니다. 알고리즘의 실제 구현을 변경하지 않고 올바른 k를 선택하여 임의로 작은 수준으로 확률을 얻을 수 있습니다.

우리는 해시 맵 에 높은 확률로 O (1) 액세스 권한이 있다고 말함으로써 이것에 대해 이야기합니다.


답변

최악의 동작을 평균 (예상) 런타임과 혼합 한 것 같습니다. 전자는 일반적으로 해시 테이블에 대해 실제로 O (n)입니다 (즉, 완벽한 해싱을 사용하지 않음). 실제로는 거의 관련이 없습니다.

반 괜찮은 해시와 결합 된 모든 신뢰할 수있는 해시 테이블 구현은 예상되는 경우 매우 작은 차이 범위 내에서 매우 작은 요소 (실제로 2)로 O (1)의 검색 성능을 갖습니다.


답변

Java에서 HashMap은 hashCode를 사용하여 버킷을 찾습니다. 각 버킷은 해당 버킷에있는 항목의 목록입니다. 비교를 위해 등호를 사용하여 항목을 스캔합니다. 항목을 추가 할 때 특정로드 백분율에 도달하면 HashMap의 크기가 조정됩니다.

따라서 때로는 몇 가지 항목과 비교해야하지만 일반적으로 O (n)보다 O (1)에 훨씬 가깝습니다. 실용적인 목적으로, 당신이 알아야 할 전부입니다.


답변

o (1)은 각 룩업이 단일 항목 만 검사한다는 것을 의미하지는 않습니다. 이는 검사 된 평균 항목 수가 컨테이너의 항목 수에 따라 일정하게 유지됨을 의미합니다. 따라서 100 개의 항목이있는 컨테이너에서 항목을 찾기 위해 평균 4 번의 비교를 수행하는 경우 10000 개의 항목이있는 컨테이너에서 항목을 찾기 위해 평균 4 번의 비교를 수행해야합니다. 특히 해시 테이블이 다시 해시되는 지점과 매우 적은 수의 항목이있는 지점 주변의 분산).

따라서 버킷 당 평균 키 수가 고정 범위 내에있는 한 충돌로 인해 컨테이너에서 o (1) 작업을 수행 할 수 없습니다.


답변

나는 이것이 오래된 질문이라는 것을 알고 있지만 실제로 그것에 대한 새로운 대답이 있습니다.

해시 맵은 실제로 O(1)엄밀히 말하면 정확하지 않습니다. 요소 수는 임의로 커질수록 일정한 시간에 검색 할 수 없으므로 O 표기법은 숫자로 정의됩니다. 임의로 커짐).

그러나 O(n)버킷을 선형 목록으로 구현해야한다는 규칙이 없기 때문에 실시간 복잡성이 따르는 것은 아닙니다 .

실제로 Java 8은 버킷 TreeMaps이 임계 값을 초과 하면 버킷을 구현 하여 실제 시간을 만듭니다 O(log n).


답변

버킷 수 (b라고 함)가 일정하게 유지되면 (일반적인 경우) 조회는 실제로 O (n)입니다.

n이 커짐에 따라 각 버킷의 요소 수는 평균 n / b입니다. 충돌 해결이 일반적인 방법 중 하나 (예 : 링크 된 목록) 중 하나로 수행되면 조회는 O (n / b) = O (n)입니다.

O 표기법은 n이 커지면 어떻게되는지에 관한 것입니다. 특정 알고리즘에 적용하면 오해의 소지가 있으며 해시 테이블이 그 예입니다. 처리 할 요소 수에 따라 버킷 수를 선택합니다. n이 b와 거의 같은 크기 인 경우 조회는 대략 일정한 시간이지만 O는 n → ∞로 한계로 정의되므로 O (1)이라고 부를 수 없습니다.


답변

O(1+n/k)k버킷 수는 어디에 있습니까 ?

구현 설정하면 k = n/alpha다음은 O(1+alpha) = O(1)이후 alpha일정입니다.