HashTables는 충돌에 어떻게 대처합니까?
에서 A가 A라는 을 들었다HashTable
는 새로운 키 엔트리가 다른 키엔트리와 충돌할 경우 새로운 엔트리를 "next available" 버킷에 배치합니다.
how how how 。HashTable
콜리젼 키를 사용하여 콜리젼을 호출할 때 이 콜리젼이 발생한 경우에도 올바른 값이 반환됩니다.
★★★★★★★★★★★★★★★★★★★★★★★★.Keys
String
및 " " "hashCode()
say Java에 합니다.
, 「」를 참조해 주세요).HashMap
★★★★★★★★★★★★★★★★★」Dictionary
충돌에 대처하기 위한 전략은 무엇입니까?
심지어 소수와 관련된 음표도 봤어!Google 검색에서 정보가 명확하지 않습니다.
해시 테이블은 두 가지 방법 중 하나로 충돌을 처리합니다.
옵션 1: 각 버킷에 해당 버킷에 해시된 요소의 링크 목록이 포함되도록 합니다.그렇기 때문에 부정한 해시 함수로 인해 해시 테이블 조회가 매우 느려질 수 있습니다.
옵션 2: 해시 테이블엔트리가 모두 가득 찬 경우 해시 테이블은 보유하고 있는 버킷의 수를 늘린 후 테이블 내의 모든 요소를 재배포할 수 있습니다.해시 함수는 정수를 반환하고 해시 테이블은 해시 함수의 결과를 가져와 버킷에 확실하게 도달할 수 있도록 테이블 크기에 맞게 수정해야 합니다.따라서 크기를 늘리면 모듈로 계산이 재해시되고 실행됩니다.이 계산은 운이 좋으면 개체를 다른 버킷으로 전송할 수 있습니다.
Java는 해시 테이블 구현에서 옵션1과 옵션2를 모두 사용합니다.
"해시 테이블이 새 키 항목이 다른 키 항목과 충돌할 경우 '다음 사용 가능한' 버킷에 새 항목을 배치합니다."에 대해 설명한 경우, 해시 테이블의 충돌 해결의 개방형 주소 지정 전략에 대해 설명합니다.
해시 테이블에는 충돌을 해결하기 위한 몇 가지 전략이 있습니다.
빅 메서드의 첫 번째 종류에서는 키(또는 키에 대한 포인터)를 관련 값과 함께 테이블에 저장해야 합니다.이러한 방법은 다음과 같습니다.
- 개별 체인
- 오픈 어드레싱
- 통합 해시
- 뻐꾸기 해싱
- 로빈 후드 해싱
- 2가지 선택 해싱
- 홉스코치 해시
충돌을 처리하는 또 다른 중요한 방법은 동적 크기 조정입니다. 이 방법에는 다음과 같은 여러 가지 방법이 있습니다.
- 모든 항목을 복사하여 크기 조정
- 증분 크기 조정
- 단조로운 키
편집: 위는 wiki_hash_table에서 차용한 것입니다.여기서 자세한 정보를 보실 수 있습니다.
충돌을 처리하는 데는 여러 가지 기술을 사용할 수 있습니다.그 중 몇 가지를 설명하겠습니다.
체인:체인에서는 어레이 인덱스를 사용하여 값을 저장합니다.두 번째 값의 해시 코드가 동일한 인덱스를 가리킬 경우 해당 인덱스 값을 링크된 목록으로 대체하고 해당 인덱스를 가리키는 모든 값은 링크된 목록에 저장되며 실제 배열 인덱스는 링크된 목록의 선두를 가리킵니다.그러나 배열 인덱스를 가리키는 해시 코드가 하나만 있는 경우 값은 해당 인덱스에 직접 저장됩니다.값을 가져오는 동안 동일한 논리가 적용됩니다.이는 충돌을 피하기 위해 Java HashMap/Hashtable에서 사용됩니다.
선형 프로브:이 기술은 테이블에 저장할 값보다 더 많은 인덱스가 있을 때 사용됩니다.선형 프로빙 기술은 빈 슬롯이 발견될 때까지 계속 증가한다는 개념에서 작동합니다.의사 코드는 다음과 같습니다.
index = h(k)
while( val(index) is occupied)
index = (index+1) mod n
이중 해시 기법:이 기술에서는 2개의 해시함수 h1(k)과 h2(k)를 사용합니다.h1(k)의 슬롯이 점유되어 있는 경우 인덱스를 증가시키기 위해 두 번째 해시 함수 h2(k)가 사용됩니다.의사 코드는 다음과 같습니다.
index = h1(k)
while( val(index) is occupied)
index = (index + h2(k)) mod n
선형 프로브 및 이중 해시 기술은 개방형 주소 지정 기술의 일부이며, 사용 가능한 슬롯이 추가할 항목 수보다 많은 경우에만 사용할 수 있습니다.여기에는 추가 구조가 사용되지 않기 때문에 체인보다 메모리가 적게 소요되지만 빈 슬롯을 찾을 때까지 이동이 많기 때문에 느립니다.또, 오픈 어드레싱 기술에서는, 슬롯으로부터 아이템을 떼어냈을 때에, 아이템이 여기서 제거되고 있는 것을 나타내는 표석을 붙여 빈 것을 나타냅니다.
상세한 것에 대하여는, 이 사이트를 참조해 주세요.
최근 HackerNews에 게재된 블로그 투고를 꼭 읽어보시기 바랍니다.Java에서의 HashMap 작동 방식
한마디로 답은
두 개의 다른 HashMap 키 객체에 동일한 해시 코드가 있으면 어떻게 됩니까?
이러한 노드는 동일한 버킷에 저장되지만 링크 목록의 다음 노드는 저장되지 않습니다.Keys equals() 메서드는 HashMap에서 올바른 키 값 쌍을 식별하기 위해 사용됩니다.
학위 수업에서 HashTable이 새 키 항목이 다른 키 항목과 충돌할 경우 '다음 사용 가능한' 버킷에 새 항목을 배치한다고 들었습니다.
적어도 Oracle JDK에서는 그렇지 않습니다(API 구현에 따라 다를 수 있음).대신 각 버킷에는 Java 8 이전의 엔트리와 Java 8 이상의 균형 트리가 링크되어 있습니다.
그러면 HashTable은 충돌 키로 콜백할 때 이 충돌이 발생해도 올바른 값을 어떻게 반환합니까?
, 이렇게 요.equals()
을 사용법
자체 해시 함수를 구현하여 검색 테이블(HashMap 또는 사전)의 일부로 사용하는 경우 충돌에 대처하기 위한 전략은 무엇입니까?
장점과 단점이 다른 다양한 충돌 처리 전략이 있습니다.해시 테이블에 대한 위키피디아의 항목은 좋은 개요를 제공합니다.
Java 8 이후 업데이트: Java 8은 충돌 처리에 자체 균형 트리를 사용하여 최악의 경우를 O(n)에서 O(log n)로 개선했습니다.자가 균형 트리의 사용은 링크 목록을 사용하는 체인(Java 7까지 사용)보다 개선되어 Java 8에서 도입되었으며 룩업에 O(n)의 최악의 경우가 있습니다(리스트를 통과할 필요가 있기 때문에).
질문의 두 번째 부분에 답변하려면 해시맵의 기본 배열에 지정된 인덱스에 지정된 요소를 매핑하여 삽입해야 합니다. 그러나 충돌이 발생할 경우 기본 배열에 교체되는 것이 아니라 보조 데이터 구조에 저장된 모든 요소를 유지해야 합니다.이것은 보통 각 어레이 컴포넌트(슬롯)를 세컨더리 데이터 구조(버킷이라고도 함)로 하고 요소를 지정된 어레이 인덱스에 있는 버킷에 추가합니다(버킷에 키가 존재하지 않는 경우 키가 교체됩니다).
조회 중에 키가 대응하는 배열 인덱스로 해시되고 지정된 버킷의 (정확한) 키와 일치하는 요소를 검색합니다.버킷은 충돌(콤파어 키 직접)을 처리할 필요가 없기 때문에 충돌 문제는 해결되지만 세컨더리 데이터 구조에서 삽입 및 검색을 수행해야 합니다.키 포인트는 해시맵에는 키와 값이 모두 저장되어 있기 때문에 해시가 충돌하더라도 버킷 내에서 키가 직접 비교되어 동등함을 확인할 수 있다는 것입니다.
콜리션 처리는 콜리션 처리가 없는 경우 O(1)에서 체인을 위한 O(n) 및 자기 균형 트리를 위한 O(log n)로 삽입 및 룩업의 최악의 성능을 가져옵니다.
참고 자료:
Java 8은 높은 충돌에 대비하여 다음과 같은 HashMap 객체의 개선/변경을 제공합니다.
Java 7에서 추가된 대체 문자열 해시 함수가 제거되었습니다.
다수의 충돌 키가 포함된 버킷은 특정 임계값에 도달한 후 링크된 목록 대신 균형 잡힌 트리에 해당 항목을 저장합니다.
상기의 변경에 의해, 최악의 경우에서도 O(log(n)의 퍼포먼스가 보증됩니다(https://www.nagarro.com/en/blog/post/24/performance-improvement-for-hashmap-in-java-8)).
키가 짝수인지, 특히 같은 버킷에 여러 요소가 있는지 여부를 확인하려면 equals 방식을 사용합니다.
(Sun/Oracle/OpenJDK 구현에서) Java의 HashMap이 사용하는 알고리즘에 대해 약간의 혼란이 있으므로, 관련 소스 코드 스니펫(Ubuntu의 OpenJDK, 1.6.0_20에서):
/**
* Returns the entry associated with the specified key in the
* HashMap. Returns null if the HashMap contains no mapping
* for the key.
*/
final Entry<K,V> getEntry(Object key) {
int hash = (key == null) ? 0 : hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
메서드 ~때를 들어, cite 355 ~371).예를 들어 다음과 같습니다.get()
,containsKey()
리리른른른른른 른여기서 for 루프는 엔트리 객체에 의해 형성된 링크된 목록을 통과합니다.
엔트리 오브젝트의 코드(행 691-705 + 759)는 다음과 같습니다.
static class Entry<K,V> implements Map.Entry<K,V> {
final K key;
V value;
Entry<K,V> next;
final int hash;
/**
* Creates new entry.
*/
Entry(int h, K k, V v, Entry<K,V> n) {
value = v;
next = n;
key = k;
hash = h;
}
// (methods left away, they are straight-forward implementations of Map.Entry)
}
이 직후에addEntry()
★★★★
/**
* Adds a new entry with the specified key, value and hash code to
* the specified bucket. It is the responsibility of this
* method to resize the table if appropriate.
*
* Subclass overrides this to alter the behavior of put method.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
if (size++ >= threshold)
resize(2 * table.length);
}
버킷 전면에 새로운 엔트리가 추가되고 오래된 첫 번째 엔트리에 대한 링크가 표시됩니다(또는 그러한 엔트리가 없는 경우에는 늘).마찬가지로,removeEntryForKey()
method는 목록을 통과하여 1개의 엔트리만 삭제하고 나머지 엔트리는 그대로 둡니다.
가 '버킷'에서 스럽습니다.★★★★★★★★★★★★★★★★,_20
로로 합니다._22
2 2개
(이 코드는 (c) 1997-2007 Sun Microsystems로 GPL에서 사용할 수 있습니다.단, 더 나은 복사를 위해서는 Sun/Oracle의 각 JDK의 src.zip에 포함된 원본 파일 및 OpenJDK에 포함된 원본 파일을 사용하십시오.)
(Java)는 실행만 가능합니다.put()
★★★★★★★★★★★★★★★★★」get()
의 JAVA에 에 원하는을 쉽게 할 수 .hashCode()
모든 오브젝트에 의해 구현되는 메서드.자신만의 인터페이스를 쉽게 만들 수 있습니다.
interface Hashable {
int getHash();
}
필요에 따라서, 키를 사용해 실장하도록 강제합니다.
public class Hashtable<K, V> {
private static class Entry<K,V> {
private final K key;
private final V val;
Entry(K key, V val) {
this.key = key;
this.val = val;
}
}
private static int BUCKET_COUNT = 13;
@SuppressWarnings("unchecked")
private List<Entry>[] buckets = new List[BUCKET_COUNT];
public Hashtable() {
for (int i = 0, l = buckets.length; i < l; i++) {
buckets[i] = new ArrayList<Entry<K,V>>();
}
}
public V get(K key) {
int b = key.hashCode() % BUCKET_COUNT;
List<Entry> entries = buckets[b];
for (Entry e: entries) {
if (e.key.equals(key)) {
return e.val;
}
}
return null;
}
public void put(K key, V val) {
int b = key.hashCode() % BUCKET_COUNT;
List<Entry> entries = buckets[b];
entries.add(new Entry<K,V>(key, val));
}
}
충돌 해결 방법에는 여러 가지가 있습니다.그 중에는 분리 체인, 오픈 어드레싱, 로빈 후드 해싱, Cuckoo 해싱 등이 있습니다.
Java는 해시 테이블의 충돌을 해결하기 위해 별도 체인을 사용합니다.다음은 그 원리에 대한 훌륭한 링크입니다.http://javapapers.com/core-java/java-hashtable/
언급URL : https://stackoverflow.com/questions/4980757/how-do-hashtables-deal-with-collisions
'source' 카테고리의 다른 글
Python을 사용하여 HTML 파일에서 텍스트 추출 (0) | 2022.12.18 |
---|---|
최대 절전 모드에서 결과 집합을 추출할 수 없습니다. (0) | 2022.12.18 |
레코드를 단일 레코드로 선택하여 시간 차이를 확인하는 방법 (0) | 2022.12.18 |
네이티브 코드를 호출하기 위해 유고 인민군 대신 JNI를 사용하시겠습니까? (0) | 2022.12.18 |
LOCK TABLES가 테이블이 잠기지 않았다고 말한 후 UNION 쿼리에서 선택 (0) | 2022.12.18 |