SO re Java 해시 맵 및 O(1)
조회 시간 에 대한 흥미로운 주장을 보았습니다 . 누군가 왜 이것이 그렇게 설명 할 수 있습니까? 이러한 해시 맵이 내가 구입 한 해시 알고리즘과 크게 다르지 않으면 충돌이 포함 된 데이터 세트가 항상 존재해야합니다.
어떤 경우에는 조회가 O(n)
아닌 것 O(1)
입니다.
사람은인지 설명 할 수 있다 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) 작업을 수행 할 수 없습니다.
버킷 수 (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
일정입니다.
우리는 O (1) 인 해시 테이블 조회의 표준 설명이 엄격한 최악의 성능이 아니라 평균 예상 시간을 참조 함을 확립했습니다. 체인과의 충돌을 해결하는 해시 테이블 (예 : Java 해시 맵)의 경우 해시 함수가 좋은 O (1 + α)입니다 . . 여기서 α는 테이블의로드 계수입니다. 저장하는 객체의 수가 테이블 크기보다 큰 상수보다 크지 않은 한 여전히 일정합니다.
엄밀히 말하면 결정적 해시 함수에 대해 O ( n ) 조회 가 필요한 입력을 구성 할 수 있다고 설명했습니다 . 그러나 평균 검색 시간과 다른 최악의 예상 시간 을 고려하는 것도 흥미 롭습니다 . 체인을 사용 하면 α = 1 일 때 O (1 + 가장 긴 체인의 길이)입니다 (예 : Θ (log n / log log n )).
예상되는 최악의 경우 조회를 일정하게 유지하는 이론적 인 방법에 관심이 있다면 다른 해시 테이블과의 충돌을 재귀 적으로 해결하는 동적 완벽한 해싱 에 대해 읽을 수 있습니다 !
HashMap 내부의 요소는 연결된 목록 (노드)의 배열로 저장되며, 배열의 각 연결된 목록은 하나 이상의 키의 고유 한 해시 값에 대한 버킷을 나타냅니다.
HashMap에 항목을 추가하는 동안 키의 해시 코드는 배열에서 버킷의 위치를 결정하는 데 사용됩니다.
location = (arraylength - 1) & keyhashcode
여기서 &는 비트 AND 연산자를 나타냅니다.
예를 들면 다음과 같습니다. 100 & "ABC".hashCode() = 64 (location of the bucket for the key "ABC")
get 작업 중에 동일한 방법을 사용하여 키의 버킷 위치를 결정합니다. 최상의 경우 각 키에는 고유 한 해시 코드가 있고 각 키에 대해 고유 한 버킷이 발생합니다.이 경우 get 메소드는 버킷 위치를 결정하고 상수 O (1) 인 값을 검색하는 데만 시간을 소비합니다.
최악의 경우 모든 키에 동일한 해시 코드가 있고 동일한 버킷에 저장되므로 전체 목록을 순회하여 O (n)이됩니다.
Java 8의 경우, 크기가 8보다 커지면 Linked List 버킷이 TreeMap으로 바뀌어 최악의 검색 효율이 O (log n)로 줄어 듭니다.
이것은 알고리즘 자체가 실제로 변경되지 않기 때문에 기본적으로 대부분의 프로그래밍 언어에서 대부분의 해시 테이블 구현에 적용됩니다.
테이블에 충돌이 없으면 단일 조회 만 수행하면되므로 실행 시간은 O (1)입니다. 충돌이있는 경우 둘 이상의 조회를 수행해야하므로 성능이 O (n)으로 낮아집니다.
실질적인 관점에서 학문을 제외하고 HashMaps는 성능에 영향을 미치지 않는 것으로 인정되어야합니다 (프로필러가 달리 지시하지 않는 한).
이론적 인 경우에만 해시 코드가 항상 다르고 모든 해시 코드에 대한 버킷도 다른 경우 O (1)이 존재합니다. 그렇지 않으면, 그것은 해시 맵의 증분에서 일정한 순서이며, 검색 순서는 일정하게 유지됩니다.
물론 해시 맵의 성능은 주어진 객체에 대한 hashCode () 함수의 품질에 따라 달라집니다. 그러나 충돌 가능성이 매우 낮도록 함수를 구현하면 성능이 매우 우수합니다 ( 가능한 모든 경우 에 O (1)는 아니지만 대부분의 경우).
예를 들어, Oracle JRE의 기본 구현은 난수 (오브젝트 인스턴스에 저장되어 변경되지 않도록하지만 바이어스 된 잠금을 비활성화하지만 다른 논의 임)를 사용하므로 충돌 가능성이 있습니다. 매우 낮은.
hashCode % tableSize
충돌이 발생할 수 있음을 통해 결정됩니다 . 32 비트를 완전히 사용하지 못합니다. 이것은 해시 테이블의 요점입니다. 큰 인덱싱 공간을 작은 것으로 줄입니다.