HashSet <T> 대 Dictionary <K, V> 항목이 있는지 찾기위한 검색 시간


103
HashSet<T> t = new HashSet<T>();
// add 10 million items


Dictionary<K, V> t = new Dictionary<K, V>();
// add 10 million items.

누구의 .Contains방법이 더 빨리 돌아 올까요?

명확히하기 위해 제 요구 사항은 데이터 구조에 존재하는지 확인해야하는 천만 개의 개체 (실제로 문자열)가 있다는 것입니다. 나는 절대 반복하지 않을 것입니다.


1
1 단계 : 둘 다 동일한 작업을 수행하는지 확인 (이 경우 두 컬렉션은 서로 다른 목적을위한 것임) 2 단계 : 문서를 참조하고 점근 적 복잡성에 대해 만족하는지 확인합니다. 3 단계 : 더 걱정할 필요가 있다고 생각되면 자신을 측정 한 다음 그와 함께 벤치 마크를 게시하는 질문을합니다. 귀하의 경우에는 첫 번째 단계에서 질문이 무의미 해집니다.
nawfal

답변:


153

HashSet vs List vs Dictionary 성능 테스트, 여기 에서 가져 왔습니다 .

1000000 개의 개체 추가 (중복을 확인하지 않고)

10000 컬렉션의 절반 개체에 대한 검사 포함

10000 컬렉션의 절반 개체 제거


9
훌륭한 분석! .Contains for Dictionary는 너무 빠르기 때문에 OP의 경우 HashSet을 사용하는 것의 이점이 전혀 없습니다.
EtherDragon 2012

2
네, OP와 같은 질문이있었습니다. 다른 이유로 사용중인 사전이 이미 있으며 ContainsKey를 사용하는 대신 Hashset으로 변경하는 것이 도움이되는지 알고 싶었습니다. 둘 다 너무 빠르기 때문에 대답은 아니오 인 것 같습니다.
FistOfFury 2012 년

4
이전 주석이 암시하는 것과는 반대로 HashSet으로 전환해야합니다. 원하는 것을 제공하기 때문에 HashSet으로 전환해야합니다 : 값 세트 저장 (일종의 매핑 유지와 반대). 이 답변은 사전에 비해 성능에 부정적인 영향이 없음을 나타냅니다.
Francois Beaussier

이 답변은 HashSet과 Dictionary의 성능이 어떻게 비교되는지 알려주지 않습니다. 그것은 모두 List ..보다 빠르다는 것입니다. 음 ... yeah! 명백하게! HashSet은 3 배 더 빠를 수 있으며 관련 테스트가 "즉시 적입니다 ... 목록에 비해 "로 축소 되었기 때문에 알 수 없습니다 .
브론 달

71

Dictionary<TKey, TValue>두 번째 경우 를 의미한다고 생각 합니까?HashTable제네릭이 아닌 클래스입니다.

실제 요구 사항에 따라 작업에 적합한 컬렉션을 선택해야합니다. 실제로 마십시오 원하는 값으로 각 키를 매핑? 그렇다면 Dictionary<,>. 다음과 같은 경우 에만 일련의 사용으로 신경HashSet<> .

나는 기대 HashSet<T>.ContainsDictionary<TKey, TValue>.ContainsKey그들이 근본적으로 동일한 알고리즘을 사용 - 기본적으로 동일한을 수행하기 위해 (당신이 현명하게 당신의 사전을 사용하는 가정하고 비교 작업있는). 항목 Dictionary<,>이 커지면 캐시를을 사용하는 Dictionary<,>것보다 캐시를 날려 버릴 가능성이 더 커지지 HashSet<>만 단순히 잘못된 데이터 유형을 선택하는 고통과 비교할 때 중요하지 않을 것으로 예상합니다. 달성하려고.


예, Dictionary <TKey, TValue>를 의미했습니다. 나는 아니라 데이터 구조에서 항목의 존재, 검색에 대한 걱정 모두 .
halivingston

3
@halivingston이 경우 HashSet을 사용하십시오. 그것이 당신이 필요 로하는 전부 라는 것을 분명히 합니다.
Jon Skeet

2
알았어 고마워. 실제로 지금 HashSet <TKey>가 있고 메모리에도 Dictionary <Tkey, TValue>의 복제본이 있습니다. 먼저 HashSet에 포함 된 다음 Dictionary <TKey, TValue>에서 값을 검색합니다. 지금은 무한한 메모리가 있지만 곧 메모리가 제한 될까봐 걱정이됩니다. 우리 팀은 메모리에서이 중복 항목을 제거하도록 요청할 것입니다.이 시점에서 저는 Dictionary <TKey, TValue>를 사용해야합니다.
halivingston

4
Dictionary에 ContainsKey 기능이 있다는 것을 알고 있습니까? 데이터를 복제하는 이유는 무엇입니까?
Blindy

8
사전에 데이터가 이미있는 경우 첫 번째 주석이 분명히 올바르지 않습니다. 키도 값과 연결해야합니다. 특정 코드에는 해당 되지 않을 수도 있지만 이는 관련이 없습니다. 이미 Dictionary다른 이유가있는 경우이를 사용해야합니다.
Jon Skeet

7

Dictionary <TKey, TValue>에 대한 MSDN 설명서에서

" Dictionary 클래스가 해시 테이블로 구현되기 때문에 키를 사용하여 값을 검색하는 것은 O (1)에 가까워 매우 빠릅니다 . "

메모 :

"검색 속도는 TKey에 지정된 유형의 해싱 알고리즘 품질에 따라 다릅니다."

귀하의 질문 / 게시물이 오래되었다는 것을 알고 있지만 비슷한 질문에 대한 답변을 찾는 동안이 문제를 발견했습니다.

도움이 되었기를 바랍니다. 자세한 내용을 보려면 비고 섹션으로 스크롤 하십시오. https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx


4

이들은 다른 데이터 구조입니다. 또한 일반 버전의 HashTable.

HashSet키-값 쌍을 포함 하는 HashTable(또는 Dictionary) 유형 T의 값을 포함합니다 . 따라서 저장해야 할 데이터에 대한 수집을 선택해야합니다.


0

이 질문에 대해 허용 된 답변은 질문에 대한 올바른 답변이 아닙니다! 정답을 제공하지만 그 답은 그들이 제공 한 증거로 보여지지 않습니다.

그 대답이 보여주는 것은 Dictionary또는 에 대한 키 조회 HashSetList. 사실이지만 흥미롭지도 놀랍지도 않으며 동일한 속도 를 가지고 있다는 증거도 아닙니다 .

조회 시간을 비교하기 위해 아래 코드를 실행했으며 내 결론은 실제로 동일한 속도라는 것입니다. (또는 적어도 차이가 있다면 그 차이는 그 속도의 표준 편차 내에있는 것입니다)

구체적으로,이 테스트에서 100,000,000 조회는 두 가지 모두에 대해 10 초에서 11.5 초 사이에 걸렸습니다.

테스트 코드 :

private const int TestReps = 100_000_000;
[Test]
public void CompareHashSetContainsVersusDictionaryContainsKey()
{
    for (int j = 0; j < 10; j++)
    {
        var rand = new Random();
        var dict = new Dictionary<int, int>();
        var hash = new HashSet<int>();

        for (int i = 0; i < TestReps; i++)
        {
            var key = rand.Next();
            var value = rand.Next();
            hash.Add(key);
            dict.TryAdd(key, value);
        }

        var testPoints = Enumerable.Repeat(1, TestReps).Select(_ => rand.Next()).ToArray();
        var timer = new Stopwatch();
        var total = 0;
        
        timer.Restart();
            for (int i = 0; i < TestReps; i++)
            {
                var newKey = testPoints[i];
                if (hash.Contains(newKey))
                {
                    total++;
                }
            }
        Console.WriteLine(timer.Elapsed);
        
        var target = total;
        Assert.That(total == target);
        

        timer.Restart();
            for (int i = 0; i < TestReps; i++)
            {
                var newKey = testPoints[i];
                if (dict.ContainsKey(newKey))
                {
                    total++;
                }
            }
        Console.WriteLine(timer.Elapsed);

        Assert.That(total == target * 2);
        Console.WriteLine("Set");
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.