2010-02-10 4 views
15

테이블에 키를 입력해야하는 사용자 지정 개체에 문제가 있습니다. 고유 한 숫자 키를 생성해야합니다. 나는 충돌 문제를 겪고 있으며 사전을 활용하여 나를 도울 수 있는지 궁금합니다. 다음과 같은 객체가 있다고 가정 해 보겠습니다..NET 사전이 충돌을 얼마나 잘 해결합니까?

class Thingy 
{ 
    public string Foo; 
    public string Bar; 
    public string Others; 
} 

등으로 더 많은 필드가 있다고 가정합니다. Foo와 Bar는 필자의 주요 필드라고 할 수 있습니다. 두 Thingys가 같으면 두 객체를 동일하게 간주해야합니다 (하나는 다른 필드로 업데이트 될 수 있고 Others 필드는 업데이트됩니다). 그래서 다음과 같습니다 :

public override bool Equals(object obj) 
{ 
    Thingy thing = (Thingy)obj; // yes I do type check first 
    return (this.Foo == thing.Foo && this.Bar == thing.Bar); 
} 

public override int GetHashCode() 
{ 
    return (this.Foo + this.Bar).GetHashCode(); // using default string impl 
} 

이렇게 대부분의 경우 작동하지만 실제로 다른 두 Thingys가 동일한 해시 코드를 갖는 경우는 거의 없습니다.

내 질문은 : 내가 Thingys에 넣은 사전 <Thingy, int을 사용할 수 있으며 순차적 값을 사전에서 실제 키로 사용합니까? 드문 해시 코드 충돌을 감지 할 때 Dictionary가 My Equals 메서드를 호출하고 개체가 실제로 다르다는 것을 확인한 다음 다르게 저장하는지 궁금합니다. 나는 영상을 보았을 때 그 해시를위한 양동이를 보았고 정확한 Thingy를 검색했다. 다시 Equals를 사용하여 비교했다.

사전의 경우입니까, 아니면 해시 코드가 다른 충돌 만 해결할 수 있습니까 (해시 % 크기)? 이 방법이 효과가 없다면 어떻게 될까요?

답변

25

해시 충돌은 무결성이 아닌 성능에만 영향을줍니다.

간단한 테스트는 GetHashCode()를 변경하여 간단히 1을 반환하는 것입니다. 사전은 여전히 ​​올바르게 작동하지만 합리적인 데이터 세트를 사용하면 몹시 수행 할 것입니다.

+0

포인트를 설명하는 좋은 방법입니다. – itowlson

18

해시 충돌은 주로 정확도가 아닌 성능에 영향을 미칩니다. 따라서 Equals()이 올바르게 작동하는 한.

Dictionary은 항목을 별도의 "버킷"으로 구성하는 방법으로 해시 코드를 사용합니다. 너무 많은 항목이 동일한 해시 코드를 공유하면 성능 문제가 발생할 수 있습니다. 그러나 Equals()이 인스턴스를 올바르게 구분할 수있는 한 올바른 결과가 얻어야합니다.

해시 코드로 인해 문제가 될 수있는 곳은 변경 가능한 개체입니다.Thingy 클래스에서 사전에있는 항목에 대해 Foo 또는 Bar을 변경할 수 있으면 다음 액세스 시도에서 해당 항목을 찾지 못할 수 있습니다. 이는 현재 생성 된 해시 코드가 사전에 값을 저장하는 데 사용 된 해시 코드와 다르기 때문입니다.

+0

이것은 실제로 어떤 사전에도 해당됩니다. 모든 사전 유형은 상수 키를 사용합니다. – Joel

+0

변경 가능한 객체의 경우 일반적으로 참조 equality를 반환하므로 기본 object.Equals() 메서드 만 남기를 원합니다. 일반적으로 == 과부하가 가치 평등을 테스트하기를 원합니다. 기본 객체 인 .Equals() 만 남겨두면 변경 가능한 객체를 부작용없이 사전 키로 사용할 수 있습니다. – Bob

+2

비 변경 가능 유형의 연산자 == 무시는 일반적으로 권장되지 않습니다. MSDN 문서는'Object.Equals()'와'=='연산자를 오버라이드하고 싶은 경우를 실제로 설명합니다. http://msdn.microsoft.com/en-us/library/ms173147%28VS.80%29.aspx – LBushkin

1

GetHashCode는 충돌을 최소화해야하지만 제거되지 않아야하는 해시 테이블에서 사용하도록 설계되었습니다. 진정으로 고유 한 키를 생성해야하는 경우 GetHashCode는 합리적인 출발점이며 GUID만큼 길지는 않지만 객체의 일부로 키를 저장하고 사용 된 키 목록을 별도로 유지해야합니다.

사전 내부에서 사용할 수있는 내용을 검색 할 수는 있지만 안정적으로 작동하지 않을 수 있습니다. 예를 들어 사전에 할당 된 항목보다 많은 항목을 추가하는 경우 기본 데이터 구조는 재건되고 개별 항목은 사전의 완전히 다른 부분으로 끝날 수 있습니다.

+0

실제로 사전을 사용하는 것에 대한 의미는 객체를 사전에 키로 저장 한 다음 값으로 새로운 가장 높은 int를 저장하고 그 값을 테이블의 키로 사용한다는 것입니다. 따라서 dict의 값은 순차적 일 것이고, 객체를 찾으면 테이블의 고유 한 숫자 키를 얻을 수 있습니다. 따라서 내부 사전 구조는 부적합합니다. – Tesserex

+0

그래서 효과적으로 사전에 개체를 추가하여 개체에 추가 할 수 있습니다. 사용자가 제어 할 수있는 사용자 지정 개체로 작업하는 경우에는 가장 효율적인 방법이 아닙니다. –

관련 문제