해시 셋과리스트 성능


405

일반 HashSet<T>클래스 의 검색 성능이 일반 클래스 의 검색 성능 보다 높다는 것은 분명합니다 List<T>. 해시 기반 키를 List<T>클래스 의 선형 접근 방식과 비교하십시오 .

그러나 해시 키를 계산하는 데 자체 CPU 사이클이 소요될 수 있으므로 소량의 항목에 대해서는 선형 검색이에 대한 실제 대안이 될 수 있습니다 HashSet<T>.

내 질문 : 손익분기 점은 어디에 있습니까?

시나리오를 단순화하고 공정하게하기 위해 List<T>클래스가 요소의 Equals()메소드를 사용하여 항목을 식별 한다고 가정합니다 .


7
조회 시간을 최소화하려면 배열과 정렬 된 배열도 고려하십시오. 이 질문에 올바르게 대답하려면 벤치 마크가 필요하지만 T에 대해 더 자세히 알려줘야합니다. 또한 HashSet 성능은 T.GetHashCode ()의 실행 시간에 영향을받을 수 있습니다.
Eldritch Conundrum

답변:


819

많은 사람들이 일단 속도가 실제로 HashSet<T>이길 우려가있는 크기에 도달하면, List<T>그것은 당신이하는 일에 달려 있다고 말합니다.

List<T>평균 5 개 항목 만 포함 한다고 가정 해 보겠습니다 . 많은 수의 사이클에 걸쳐 하나의 아이템이 각 사이클에 추가되거나 제거되면를 사용하는 것이 좋습니다 List<T>.

나는 내 컴퓨터에서 이것을 테스트했으며, 이점을 얻으려면 매우 작아야합니다 List<T>. 짧은 문자열 목록의 경우 크기 20 이후의 개체의 경우 크기 5 이후로 이점이 사라졌습니다.

1 item LIST strs time: 617ms
1 item HASHSET strs time: 1332ms

2 item LIST strs time: 781ms
2 item HASHSET strs time: 1354ms

3 item LIST strs time: 950ms
3 item HASHSET strs time: 1405ms

4 item LIST strs time: 1126ms
4 item HASHSET strs time: 1441ms

5 item LIST strs time: 1370ms
5 item HASHSET strs time: 1452ms

6 item LIST strs time: 1481ms
6 item HASHSET strs time: 1418ms

7 item LIST strs time: 1581ms
7 item HASHSET strs time: 1464ms

8 item LIST strs time: 1726ms
8 item HASHSET strs time: 1398ms

9 item LIST strs time: 1901ms
9 item HASHSET strs time: 1433ms

1 item LIST objs time: 614ms
1 item HASHSET objs time: 1993ms

4 item LIST objs time: 837ms
4 item HASHSET objs time: 1914ms

7 item LIST objs time: 1070ms
7 item HASHSET objs time: 1900ms

10 item LIST objs time: 1267ms
10 item HASHSET objs time: 1904ms

13 item LIST objs time: 1494ms
13 item HASHSET objs time: 1893ms

16 item LIST objs time: 1695ms
16 item HASHSET objs time: 1879ms

19 item LIST objs time: 1902ms
19 item HASHSET objs time: 1950ms

22 item LIST objs time: 2136ms
22 item HASHSET objs time: 1893ms

25 item LIST objs time: 2357ms
25 item HASHSET objs time: 1826ms

28 item LIST objs time: 2555ms
28 item HASHSET objs time: 1865ms

31 item LIST objs time: 2755ms
31 item HASHSET objs time: 1963ms

34 item LIST objs time: 3025ms
34 item HASHSET objs time: 1874ms

37 item LIST objs time: 3195ms
37 item HASHSET objs time: 1958ms

40 item LIST objs time: 3401ms
40 item HASHSET objs time: 1855ms

43 item LIST objs time: 3618ms
43 item HASHSET objs time: 1869ms

46 item LIST objs time: 3883ms
46 item HASHSET objs time: 2046ms

49 item LIST objs time: 4218ms
49 item HASHSET objs time: 1873ms

데이터는 그래프로 표시됩니다.

여기에 이미지 설명을 입력하십시오

코드는 다음과 같습니다.

static void Main(string[] args)
{
    int times = 10000000;


    for (int listSize = 1; listSize < 10; listSize++)
    {
        List<string> list = new List<string>();
        HashSet<string> hashset = new HashSet<string>();

        for (int i = 0; i < listSize; i++)
        {
            list.Add("string" + i.ToString());
            hashset.Add("string" + i.ToString());
        }

        Stopwatch timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < times; i++)
        {
            list.Remove("string0");
            list.Add("string0");
        }
        timer.Stop();
        Console.WriteLine(listSize.ToString() + " item LIST strs time: " + timer.ElapsedMilliseconds.ToString() + "ms");


        timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < times; i++)
        {
            hashset.Remove("string0");
            hashset.Add("string0");
        }
        timer.Stop();
        Console.WriteLine(listSize.ToString() + " item HASHSET strs time: " + timer.ElapsedMilliseconds.ToString() + "ms");
        Console.WriteLine();
    }


    for (int listSize = 1; listSize < 50; listSize+=3)
    {
        List<object> list = new List<object>();
        HashSet<object> hashset = new HashSet<object>();

        for (int i = 0; i < listSize; i++)
        {
            list.Add(new object());
            hashset.Add(new object());
        }

        object objToAddRem = list[0];

        Stopwatch timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < times; i++)
        {
            list.Remove(objToAddRem);
            list.Add(objToAddRem);
        }
        timer.Stop();
        Console.WriteLine(listSize.ToString() + " item LIST objs time: " + timer.ElapsedMilliseconds.ToString() + "ms");



        timer = new Stopwatch();
        timer.Start();
        for (int i = 0; i < times; i++)
        {
            hashset.Remove(objToAddRem);
            hashset.Add(objToAddRem);
        }
        timer.Stop();
        Console.WriteLine(listSize.ToString() + " item HASHSET objs time: " + timer.ElapsedMilliseconds.ToString() + "ms");
        Console.WriteLine();
    }

    Console.ReadLine();
}

8
정말 고맙습니다! 이것은 훌륭한 설명이며, List<T>게임 엔진 보다 더 빠르게 추가하고 제거 할 수있는 것을 찾고 있었고 , 일반적으로 많은 양의 객체가 있기 때문에 이러한 종류의 컬렉션은 완벽합니다.
redcodefinal 2018 년

17
.NET 프레임 워크에는 실제로 포함 된 항목 수에 따라 목록과 hastable 구현 간을 전환하는 컬렉션이 있습니다. HybridDictionary .
MgSam

8
MS는 비 제네릭 버전 만 사용할 수 있기 때문에 생각을 버린 것 같습니다.
MgSam

47
이 답변이 가득 차면 목록 대 해시 세트 검색 성능에 관한 원래 질문에 대답하지 못합니다. 삽입 및 제거가 얼마나 빠른지 테스트하고 있으며, 검색보다 시간과 성능이 상당히 다릅니다. .Contains를 사용하여 다시 시도하면 그래프가 크게 변경됩니다.
Robert McKee

5
@hypehuman CPU는 시스템 메모리의 데이터에서 직접 작업 할 수 없지만 메모리에서 데이터를 캐시로 가져와 작업합니다. 메모리 이동 요청과 실제로 도착하는 메모리간에 상당한 지연이 발생하므로 CPU는 종종 더 큰 연속 메모리 청크를 한 번에 이동하도록 요청합니다. 이것에 대한 아이디어는 다음 명령어에 필요한 메모리가 아마도 이전 명령어에 사용 된 메모리에 매우 가깝기 때문에 이미 캐시에 있다는 것입니다. 데이터가 메모리 전체에 흩어져 있으면 운이 좋을 확률이 줄어 듭니다.
Roy T.

70

당신은 이것을 잘못보고 있습니다. 예, List의 선형 검색은 소수의 항목에 대해 HashSet을 이길 것입니다. 그러나 성능 차이는 일반적으로 작은 컬렉션에는 중요하지 않습니다. 일반적으로 걱정해야 할 대규모 컬렉션 이며 Big-O 측면에서 생각하는 곳 입니다. 그러나 HashSet 성능에 대한 실제 병목 현상을 측정 한 경우 하이브리드 List / HashSet을 만들려고 시도 할 수 있지만 SO에 대한 질문을하지 않고 많은 경험적 성능 테스트를 수행하여이를 수행 할 수 있습니다.


5
걱정해야 할 대규모 컬렉션 . 우리는 그 질문을 when small collection becomes large enough to worry about HashSet vs List?수만, 수만, 수십억 개의 요소로 재정의 할 수 있습니까?
om-nom-nom

8
아니요, 몇 백 개 이상의 요소에서 상당한 성능 차이가 나타납니다. HashSet이 적합한 액세스 유형을 수행하는 경우 요점은 항상 HashSet을 사용합니다 (예 : 세트의 요소 X). 콜렉션이 너무 작아서 List가 빠르면 해당 조회가 매우 드 rare 실제로 응용 프로그램의 병목 현상입니다. 하나만 측정 할 수 있다면 최적화를 시도 할 수 있지만 그렇지 않으면 시간을 낭비하는 것입니다.
Eloff

15
루프에서 여러 번 히트 한 작은 컬렉션이있는 경우 어떻게합니까? 드문 시나리오는 아닙니다.
dan-gph

3
@ om-nom-nom-요점은 티핑 포인트의 HashSet<T>위치 List<T>가 중요하지 않다고 생각합니다. "
Scott Smith

66

이 두 구조를 비교하는 것은 본질적으로 무의미 성능 다르게 동작합니다. 의도를 전달하는 구조를 사용하십시오. List<T>복제본이 없다고 말하고 반복 순서가 a와 비교해도 문제가되지 않지만 상대적으로 내결함성 이 없으므로 HashSet<T>사용 List<T>하기에 여전히 좋지 않습니다.

즉, 성능의 다른 측면 을 조사하겠습니다 .

+------------+--------+-------------+-----------+----------+----------+-----------+
| Collection | Random | Containment | Insertion | Addition |  Removal | Memory    |
|            | access |             |           |          |          |           |
+------------+--------+-------------+-----------+----------+----------+-----------+
| List<T>    | O(1)   | O(n)        | O(n)      | O(1)*    | O(n)     | Lesser    |
| HashSet<T> | O(n)   | O(1)        | n/a       | O(1)     | O(1)     | Greater** |
+------------+--------+-------------+-----------+----------+----------+-----------+
  • 두 경우 모두 추가가 O (1)이지만 해시 코드를 저장하기 전에 미리 계산하는 비용이 포함되므로 HashSet에서 상대적으로 느려집니다.

  • HashSet의 뛰어난 확장 성은 메모리 비용이 있습니다. 모든 항목은 해시 코드와 함께 새 개체로 저장됩니다. 이 기사 는 당신에게 아이디어를 줄 수 있습니다.


11
내 질문 (6 년 전)은 이론적 성능 에 관한 것이 아닙니다 .
Michael Damatov

1
HashSet은 ElementAt ()을 사용하여 임의 액세스를 허용하며 O (n) 시간이라고 생각합니다. 또한 각 컬렉션이 중복을 허용하는지 여부를 테이블에 넣을 수 있습니다 (예 : 목록은하지만 해시 세트는 허용하지 않습니다).
Dan W

1
표의 @ DanW는 행동 특성이 아닌 순수한 성능을 비교하고 있습니다. ElementAt 팁 주셔서 감사합니다.
nawfal

1
ElementAt은 LINQ 확장 일뿐입니다. 추가 할 수없는 다른 방법으로는 수행 할 수없고 더 잘 최적화하지 않습니다. 다른 모든 메소드는 해당 클래스에 명시 적으로 존재하므로 ElementAt를 고려하지 않고 테이블이 더 의미가 있다고 생각합니다.
Dinerdo

이 테이블 덕분에 유스 케이스에서 대상을 활성화 / 비활성화 할 때마다 채워진 컬렉션에 대상을 추가하고 제거해야하므로 올바른 선택 (HashSet)을 수행하는 데 도움이되었습니다.
Casey Hofland

50

HashSet <> 또는 List <> 사용 여부는 컬렉션에 액세스하는 방법에 따라 다릅니다 . 품목 순서를 보증해야하는 경우 목록을 사용하십시오. 그렇지 않으면 HashSet을 사용하십시오. Microsoft가 해시 알고리즘 및 객체의 구현에 대해 걱정하게하십시오.

HashSet은 컬렉션 ( O (1)의 복잡성 또는 그 근처 ) 을 열거하지 않아도 항목에 액세스 할 수 있으며, List는 주문을 보장하므로 HashSet과 달리 일부 항목은 열거되어야합니다 (O (n)의 복잡성).


목록은 특정 요소의 색인으로 특정 요소의 오프셋을 계산할 수 있습니다 (모든 요소가 동일한 유형이고 잠재적으로 동일한 메모리 크기를 차지하기 때문). 따라서 List는 요소를 열거하지 않아도됩니다.
Lu55

@ Lu55-문제는 컬렉션에서 항목을 검색 하는 것입니다. 일반적인 시나리오는 컬렉션이 동적 이라는 것입니다. 마지막으로 특정 항목을 찾은 이후에 항목이 추가되거나 삭제되었을 수 있으므로 인덱스 가 의미가 없습니다 (변경 되었기 때문에). 당신이있는 경우 정적 (당신이 당신의 계산을 수행하는 동안 변경되지 않습니다), 또는 항목이 삭제되지 않습니다, 항상 마지막에 추가됩니다 수집을, 다음은 List상황이 - 당신은 인덱스를 기억할 수 있기 때문에 바람직하다 설명하고 있습니다.
ToolmakerSteve

HashSet을 정렬해야하는 경우 SortedSet을 사용할 수 있습니다. 여전히 목록보다 훨씬 빠릅니다.
라이브 사랑

25

이전 답변을 설명하기 위해 다른 시나리오에 대한 몇 가지 벤치 마크를 살펴 보았습니다.

  1. 작은 문자열 (12 ~ 20) (길이 5 ~ 10 자)
  2. 많은 (~ 10K) 작은 문자열
  3. 긴 문자열 (길이 200 ~ 1000 자)
  4. 많은 (~ 5K) 긴 문자열
  5. 몇 가지 정수
  6. 많은 (~ 10K) 정수

그리고 각 시나리오에 대해 나타나는 값을 찾으십시오.

  1. 목록의 시작 부분 ( "start", index 0)
  2. 목록의 시작 부분 근처 ( "초기", 색인 1)
  3. 목록 중간에 ( "중간", 색인 수 / 2)
  4. 목록 끝 근처 ( "late", index count-2)
  5. 목록 끝에서 ( "end", index count-1)

각 시나리오 전에 임의 크기의 임의 문자열 목록을 생성 한 다음 각 목록을 해시 세트에 제공했습니다. 각 시나리오는 기본적으로 10,000 번 실행되었습니다.

(의사 코드 테스트)

stopwatch.start
for X times
    exists = list.Contains(lookup);
stopwatch.stop

stopwatch.start
for X times
    exists = hashset.Contains(lookup);
stopwatch.stop

샘플 출력

Windows 7, 12GB Ram, 64 비트, Xeon 2.8GHz에서 테스트

---------- Testing few small strings ------------
Sample items: (16 total)
vgnwaloqf diwfpxbv tdcdc grfch icsjwk
...

Benchmarks:
1: hashset: late -- 100.00 % -- [Elapsed: 0.0018398 sec]
2: hashset: middle -- 104.19 % -- [Elapsed: 0.0019169 sec]
3: hashset: end -- 108.21 % -- [Elapsed: 0.0019908 sec]
4: list: early -- 144.62 % -- [Elapsed: 0.0026607 sec]
5: hashset: start -- 174.32 % -- [Elapsed: 0.0032071 sec]
6: list: middle -- 187.72 % -- [Elapsed: 0.0034536 sec]
7: list: late -- 192.66 % -- [Elapsed: 0.0035446 sec]
8: list: end -- 215.42 % -- [Elapsed: 0.0039633 sec]
9: hashset: early -- 217.95 % -- [Elapsed: 0.0040098 sec]
10: list: start -- 576.55 % -- [Elapsed: 0.0106073 sec]


---------- Testing many small strings ------------
Sample items: (10346 total)
dmnowa yshtrxorj vthjk okrxegip vwpoltck
...

Benchmarks:
1: hashset: end -- 100.00 % -- [Elapsed: 0.0017443 sec]
2: hashset: late -- 102.91 % -- [Elapsed: 0.0017951 sec]
3: hashset: middle -- 106.23 % -- [Elapsed: 0.0018529 sec]
4: list: early -- 107.49 % -- [Elapsed: 0.0018749 sec]
5: list: start -- 126.23 % -- [Elapsed: 0.0022018 sec]
6: hashset: early -- 134.11 % -- [Elapsed: 0.0023393 sec]
7: hashset: start -- 372.09 % -- [Elapsed: 0.0064903 sec]
8: list: middle -- 48,593.79 % -- [Elapsed: 0.8476214 sec]
9: list: end -- 99,020.73 % -- [Elapsed: 1.7272186 sec]
10: list: late -- 99,089.36 % -- [Elapsed: 1.7284155 sec]


---------- Testing few long strings ------------
Sample items: (19 total)
hidfymjyjtffcjmlcaoivbylakmqgoiowbgxpyhnrreodxyleehkhsofjqenyrrtlphbcnvdrbqdvji...
...

Benchmarks:
1: list: early -- 100.00 % -- [Elapsed: 0.0018266 sec]
2: list: start -- 115.76 % -- [Elapsed: 0.0021144 sec]
3: list: middle -- 143.44 % -- [Elapsed: 0.0026201 sec]
4: list: late -- 190.05 % -- [Elapsed: 0.0034715 sec]
5: list: end -- 193.78 % -- [Elapsed: 0.0035395 sec]
6: hashset: early -- 215.00 % -- [Elapsed: 0.0039271 sec]
7: hashset: end -- 248.47 % -- [Elapsed: 0.0045386 sec]
8: hashset: start -- 298.04 % -- [Elapsed: 0.005444 sec]
9: hashset: middle -- 325.63 % -- [Elapsed: 0.005948 sec]
10: hashset: late -- 431.62 % -- [Elapsed: 0.0078839 sec]


---------- Testing many long strings ------------
Sample items: (5000 total)
yrpjccgxjbketcpmnvyqvghhlnjblhgimybdygumtijtrwaromwrajlsjhxoselbucqualmhbmwnvnpnm
...

Benchmarks:
1: list: early -- 100.00 % -- [Elapsed: 0.0016211 sec]
2: list: start -- 132.73 % -- [Elapsed: 0.0021517 sec]
3: hashset: start -- 231.26 % -- [Elapsed: 0.003749 sec]
4: hashset: end -- 368.74 % -- [Elapsed: 0.0059776 sec]
5: hashset: middle -- 385.50 % -- [Elapsed: 0.0062493 sec]
6: hashset: late -- 406.23 % -- [Elapsed: 0.0065854 sec]
7: hashset: early -- 421.34 % -- [Elapsed: 0.0068304 sec]
8: list: middle -- 18,619.12 % -- [Elapsed: 0.3018345 sec]
9: list: end -- 40,942.82 % -- [Elapsed: 0.663724 sec]
10: list: late -- 41,188.19 % -- [Elapsed: 0.6677017 sec]


---------- Testing few ints ------------
Sample items: (16 total)
7266092 60668895 159021363 216428460 28007724
...

Benchmarks:
1: hashset: early -- 100.00 % -- [Elapsed: 0.0016211 sec]
2: hashset: end -- 100.45 % -- [Elapsed: 0.0016284 sec]
3: list: early -- 101.83 % -- [Elapsed: 0.0016507 sec]
4: hashset: late -- 108.95 % -- [Elapsed: 0.0017662 sec]
5: hashset: middle -- 112.29 % -- [Elapsed: 0.0018204 sec]
6: hashset: start -- 120.33 % -- [Elapsed: 0.0019506 sec]
7: list: late -- 134.45 % -- [Elapsed: 0.0021795 sec]
8: list: start -- 136.43 % -- [Elapsed: 0.0022117 sec]
9: list: end -- 169.77 % -- [Elapsed: 0.0027522 sec]
10: list: middle -- 237.94 % -- [Elapsed: 0.0038573 sec]


---------- Testing many ints ------------
Sample items: (10357 total)
370826556 569127161 101235820 792075135 270823009
...

Benchmarks:
1: list: early -- 100.00 % -- [Elapsed: 0.0015132 sec]
2: hashset: end -- 101.79 % -- [Elapsed: 0.0015403 sec]
3: hashset: early -- 102.08 % -- [Elapsed: 0.0015446 sec]
4: hashset: middle -- 103.21 % -- [Elapsed: 0.0015618 sec]
5: hashset: late -- 104.26 % -- [Elapsed: 0.0015776 sec]
6: list: start -- 126.78 % -- [Elapsed: 0.0019184 sec]
7: hashset: start -- 130.91 % -- [Elapsed: 0.0019809 sec]
8: list: middle -- 16,497.89 % -- [Elapsed: 0.2496461 sec]
9: list: end -- 32,715.52 % -- [Elapsed: 0.4950512 sec]
10: list: late -- 33,698.87 % -- [Elapsed: 0.5099313 sec]

7
흥미 롭군 이것을 실행 해 주셔서 감사합니다. 슬프게도, 이러한 논의가 불필요한 리팩토링을 유발한다고 생각합니다. 바라건대 대부분의 사람들이 취해야 할 일은 절대 최악의 시나리오에서 단일 조회를 수행하는 List데 여전히 0.17 밀리 초만 걸리고 HashSet조회 빈도가 부적당 한 수준에 도달 할 때까지 대체 할 필요가 없다는 것 입니다. 그때까지 일반적으로 List를 사용하는 것이 가장 적은 문제입니다.
Paul Walls

이것은 현재로서는 실제 정보가 아닙니다. 또는 아마도 원래 틀렸을 수도 있습니다. 2 ~ 8 자의 작은 값을 확인했습니다. List / HashSet은 각 10 개의 값에 대해 생성되었습니다 ... 30 % 동안 HashSet이 느립니다 ... List의 용량을 사용하는 경우 ~ 40 %까지 차이가 ​​있습니다. List에 지정된 용량이없는 경우에만 HashSet이 10 % 더 빨라지고 전체 목록을 추가하기 전에 각 값을 확인합니다.
Maxim

아이템 수가 4로 줄어든다면 최악의 시나리오 (10 % 차이)에서도리스트가 다시 승리합니다. 따라서 작은 문자열 모음에 HashSet을 사용하지 않는 것이 좋습니다 (<20이라고 가정하십시오). 그리고 그것은 "작은 몇 가지"테스트와 다른 점입니다.
Maxim

1
@Maxim은 실제로 내 결과가 "틀렸다"고 말할 수 없습니다. 이것이 내 컴퓨터에서 일어난 일입니다. YMMV. 사실, 나는 새로운 Win10 4.0GHz 16GB 솔리드 스테이트 컴퓨터에서 다시 ( gist.github.com/zaus/014ac9b5a78b267aa1643d63d30c7554 ) 다시 실행하여 비슷한 결과를 얻었습니다. 내가 본 테이크 아웃은 검색 키의 위치 또는 목록의 크기에 상관없이 해시 세트 성능이 더 일관된 반면 목록 성능은 더 나은 것에서 300x 이상으로 느리게 변한다는 것입니다. 그러나 PaulWalls가 처음에 언급 한 것처럼 심각한 #microoptimization에 대해 이야기합니다.
drzaus

참고로 @Maxim : dotnetfiddle.net/5taRDd- 자유롭게 놀아보세요.
drzaus 2016 년

10

손익분기 점은 해시 계산 비용에 따라 다릅니다. 해시 계산은 사소하거나 아닐 수 있습니다 ... :-) 항상 System.Collections.Specialized.HybridDictionary 클래스가 있으므로 손익 분기점에 대해 걱정할 필요가 없습니다.


1
또한 비교 비용을 고려해야합니다. Contains (T)의 경우 HashSet은 비교하기 때문에 해시 충돌과 List가 올바른 항목을 찾기 전에 살펴 보는 모든 항목을 비교합니다. T.GetHashCode ()에 의해 생성 된 해시의 분포가 항상 같은 값을 반환하는 것처럼 기본적으로 HashSet이 List와 동일한 작업을 수행하는 것처럼 고려해야합니다.
마틴 브라운

6

항상 그렇듯이 대답은 " 그것은 달려있다 "입니다. C #에 대해 이야기하는 태그에서 가정합니다.

최선의 방법은 결정하는 것입니다

  1. 데이터 세트
  2. 사용 요구 사항

테스트 사례를 작성하십시오.

또한 목록을 정렬하는 방법 (정렬 된 경우), 비교해야 할 종류, 목록의 특정 개체에 대한 "비교"작업에 걸리는 시간 또는 사용하려는 방법에 따라 다릅니다. 수집.

일반적으로 선택하는 가장 좋은 방법은 작업중인 데이터의 크기를 기준으로하는 것이 아니라 액세스하려는 방식에 따라 다릅니다. 특정 문자열 또는 다른 데이터와 관련된 각 데이터가 있습니까? 해시 기반 컬렉션이 가장 좋습니다. 저장하는 데이터의 순서가 중요합니까, 아니면 모든 데이터에 동시에 액세스해야합니까? 그러면 일반 목록이 더 나을 수 있습니다.

추가 :

물론 위의 의견은 '성능'이 데이터 액세스를 의미한다고 가정합니다. 고려해야 할 사항 : "성능"이라고 말할 때 무엇을 찾고 있습니까? 성과 개별 가치가 조회됩니까? 대규모 (10000, 100000 이상) 값 세트를 관리합니까? 데이터 구조를 데이터로 채우는 성능입니까? 데이터를 삭제 하시겠습니까? 개별 데이터 비트에 액세스하십니까? 값을 바꾸시겠습니까? 값을 반복합니까? 메모리 사용량? 데이터 복사 속도? 예를 들어 문자열 값으로 데이터에 액세스하지만 주요 성능 요구 사항이 최소 메모리 사용량 인 경우 충돌하는 디자인 문제가있을 수 있습니다.


5

중단 점을 자동으로 감지하고 널값을 허용하는 HybridDictionary를 사용하여 HashSet과 동일하게 만들 수 있습니다.


1
아이디어를 위해 이것을 찬성했지만 오늘날 아무도 이것을 사용하지 마십시오. 제네릭이 아닌 사람들에게 거부하십시오. 또한 사전은 키-값 매핑이며 설정되지 않습니다.
nawfal

4

때에 따라 다르지. 정답이 실제로 중요한 경우 프로파일 링을 수행하고 알아보십시오. 세트에 특정 개수 이상의 요소가 있다고 확신하지 않으면 목록으로 이동하십시오. 숫자가 제한이 없으면 HashSet을 사용하십시오.


3

해싱하는 내용에 따라 다릅니다. 키가 정수이면 HashSet이 더 빠르기 전에 많은 항목이 필요하지 않을 수 있습니다. 문자열에 키를 입력하면 속도가 느려지고 입력 문자열에 따라 다릅니다.

확실히 벤치 마크를 쉽게 만들 수 있습니까?


3

고려하지 않은 한 가지 요소는 GetHashcode () 함수의 견고성입니다. 완벽한 해시 기능으로 HashSet은 더 나은 검색 성능을 제공합니다. 그러나 해시 함수가 감소함에 따라 HashSet 검색 시간도 줄어 듭니다.


0

목록 구현, CPU 아키텍처, JVM, 루프 시맨틱, 등가 방법의 복잡성 등 많은 요인에 따라 달라집니다 ... 목록을 효과적으로 벤치마킹 할 정도로 충분히 커질 때까지 (1000 개 이상의 요소), 해시 기반 바이너리 룩업은 선형 검색을 물리 치고, 그 차이는 거기에서 확대됩니다.

도움이 되었기를 바랍니다!


1
JVM ... 또는 CLR :-)
bvgheluwe 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.