SortedList <>, SortedDictionary <> 및 Dictionary <>


100

나는 그것을 찾을 수 SortedList<TKey, TValue> SortedDictionary<TKey, TValue>Dictionary<TKey, TValue>같은 인터페이스를 구현합니다.

  1. 우리는을 선택해야하는 경우 SortedListSortedDictionary이상 Dictionary?
  2. 의 차이 무엇입니까 SortedListSortedDictionary응용 프로그램의 측면에서는?

답변:


102
  1. 둘 중 하나의 요소를 반복하면 요소가 정렬됩니다. 그리로 Dictionary<T,V>.

  2. MSDNSortedList<T,V>과 (와) 의 차이점을 해결합니다 SortedDictionary<T,V>.

SortedDictionary (TKey, TValue) 제네릭 클래스는 O (log n) 검색 이 포함 된 이진 검색 트리 입니다. 여기서 n은 사전의 요소 수입니다. 이 점에서 SortedList (TKey, TValue) 제네릭 클래스와 유사합니다. 두 클래스는 유사한 객체 모델을 가지고 있으며 둘 다 O (log n) 검색을 가지고 있습니다. 두 클래스가 다른 점은 메모리 사용과 삽입 및 제거 속도입니다.

SortedList (TKey, TValue)는 SortedDictionary (TKey, TValue)보다 적은 메모리를 사용합니다.

SortedDictionary (TKey, TValue)는 정렬되지 않은 데이터에 대한 삽입 및 제거 작업이 더 빠릅니다. SortedList (TKey, TValue)의 경우 O (n)이 아닌 O (log n)입니다.

목록이 정렬 된 데이터에서 한 번에 채워지면 SortedList (TKey, TValue)가 SortedDictionary (TKey, TValue)보다 빠릅니다.


21
또 다른 실질적인 차이점 SortedList은 인덱스로 검색 할 수 있고 (키로 검색하는 것과 반대로) SortedDictionary할 수 없다는 것입니다.
Andrew Savinykh

66

여기에 이미지 설명 입력

사전의 차이점을 언급하고 싶습니다.

위의 그림은 아날로그 Dictionary<K,V>보다 모든 경우에 동일하거나 빠르지 Sorted만 인쇄 등 요소의 순서가 필요한 경우 Sorted하나를 선택합니다.

Src : http://people.cs.aau.dk/~normark/oop-csharp/html/notes/collections-note-time-complexity-dictionaries.html


1
훌륭한 개요. 원래 질문은 아니지만 Immutable이러한 사전 의 버전 중 하나를 선택 하면 Sorted버전이 정렬되지 않은 버전보다 실제로 약 40 ~ 50 % 더 빠르다는 점에 유의해야합니다 (여전히 O(log(n))이지만 작업 당 눈에 띄게 빠름). . 그러나 입력이 정렬 된 방식에 따라 타이밍이 다를 수 있습니다. 참조 stackoverflow.com/a/30638592/111575
아벨

21

성능 테스트-SortedList vs. SortedDictionary vs. Dictionary vs. Hashtable 의 결과를 요약하면 다양한 시나리오에 대한 최상의 결과에서 최악의 결과까지 다음과 같습니다.

메모리 사용량 :

SortedList<T,T>
Hashtable
SortedDictionary<T,T>
Dictionary<T,T>

삽입 :

Dictionary<T,T>
Hashtable
SortedDictionary<T,T>
SortedList<T,T>

검색 작업 :

Hashtable
Dictionary<T,T>
SortedList<T,T>
SortedDictionary<T,T>

foreach 루프 작업

SortedList<T,T>
Dictionary<T,T>
Hashtable
SortedDictionary<T,T>

1
이러한 테스트 결과를 검토 할 때 SortedDictionary의 이유 에 의문을 제기 할 수 있습니다 .
beawolf

1
귀하의 경우 Collection필요로 sorted에 대해 당신은 잊을 수 HashtableDictionary> SortedList 가야하지만, 당신이 예상하는 경우가 종종 필요합니다 - 당신이 한 번에 당신의 컬렉션을 채우는 경우 : .Add.Remove항목 -> SortedDictionary에 대한 이동합니다.
Ama

sorted의미 를 명확히 할 필요가 있을 수 For Each MyItem in Collection있습니다. 원래 .Add항목 을 처리 한 순서대로 처리 하지 않고 a를 수행 sorted Collection하면는 Key값 에 대한 기준 (에서 정의 됨)에 따라 순서대로 처리합니다 IComparer. 예를 들어 키가 문자열 인 경우 컬렉션은 기본적으로 키의 알파벳 순서에 따라 처리되지만 언제든지 사용자 지정 정렬 규칙을 정의 할 수 있습니다.
Ama

10

제안 된 답변이 성능에 중점을두고 있음을 알 수 있습니다. 아래에 제공된 문서는 성능과 관련하여 새로운 내용을 제공하지 않지만 기본 메커니즘에 대해 설명합니다. 또한 Collection질문에 언급 된 세 가지 유형 에 초점을 맞추지 않고 System.Collections.Generic네임 스페이스 의 모든 유형을 다룹니다 .

http://geekswithblogs.net/BlackRabbitCoder/archive/2011/06/16/c.net-fundamentals-choosing-the-right-collection-class.aspx

추출물 :

사전 <>

사전은 아마도 가장 많이 사용되는 연관 컨테이너 클래스 일 것입니다. Dictionary는 내부적 으로 해시 테이블을 사용 하기 때문에 연관 조회 / 삽입 / 삭제를위한 가장 빠른 클래스입니다 . 키가 해시되기 때문에 키 유형이 GetHashCode () 및 Equals ()를 올바르게 구현 하거나 생성시 사전에 외부 IEqualityComparer를 제공해야합니다. 사전에있는 항목의 삽입 / 삭제 / 조회 시간은 일정 시간 (O (1))으로 상각됩니다. 즉, 사전이 아무리 커도 무언가를 찾는 데 걸리는 시간은 상대적으로 일정하게 유지됩니다. 이것은 고속 조회에 매우 바람직합니다. 유일한 단점 은 해시 테이블 사용의 특성상 사전이 순서가 지정되지 않았기 때문에사전에있는 항목을 순서대로 쉽게 순회 할 수 없습니다 .

SortedDictionary <>

SortedDictionary는 사용법이 Dictionary와 비슷하지만 구현이 매우 다릅니다. SortedDictionary은 키 순서대로 항목을 유지하기 위해 내부적으로 이진 트리를 사용합니다 . 정렬의 결과로 키에 사용되는 형식 은 키가 올바르게 정렬 될 수 있도록 IComparable을 올바르게 구현해야합니다 . 정렬 된 사전은 항목을 순서대로 유지하는 능력을 위해 약간의 조회 시간을 교환하므로 정렬 된 사전의 삽입 / 삭제 / 조회 시간은 로그-O (log n)입니다. 일반적으로 로그 시간을 사용하면 컬렉션 크기를 두 배로 늘릴 수 있으며 항목을 찾기 위해 추가 비교를 한 번만 수행하면됩니다. 빠른 조회를 원하지만 컬렉션을 키별로 순서대로 유지하려면 SortedDictionary를 사용하십시오.

SortedList <>

SortedList는 제네릭 컨테이너의 다른 정렬 된 연관 컨테이너 클래스입니다. 다시 한번 SortedList는 SortedDictionary와 마찬가지로 키를 사용하여 키-값 쌍을 정렬합니다 . 그러나 SortedDictionary와 달리 SortedList의 항목은 정렬 된 항목 배열로 저장됩니다.. 즉, 항목을 삭제하거나 추가하면 목록에서 모든 항목을 위나 아래로 이동할 수 있기 때문에 삽입 및 삭제가 선형 (O (n))입니다. 그러나 조회 시간은 O (log n)입니다. SortedList는 이진 검색을 사용하여 키로 목록의 항목을 찾을 수 있기 때문입니다. 그렇다면 왜 이렇게하고 싶습니까? 음, 정답은 SortedList를 미리로드하려는 경우 삽입 속도가 느리지 만 배열 인덱싱이 다음 개체 링크보다 빠르기 때문에 조회가 SortedDictionary보다 약간 빠릅니다. 다시 한 번 빠른 조회를 원하고 키에 따라 컬렉션을 순서대로 유지하고 삽입 및 삭제가 거의없는 상황에서 이것을 사용합니다.


기본 절차의 임시 요약

내가 모든 것을 올바르게 얻지 못했다고 확신하므로 피드백은 매우 환영합니다.

  • 모든 배열은 크기 n입니다.
  • 정렬되지 않은 배열 = .Add / .Remove는 O (1)이지만 .Item (i)는 O (n)입니다.
  • 정렬 된 배열 = .Add / .Remove는 O (n)이지만 .Item (i)는 O (log n)입니다.

사전

기억

KeyArray(n) -> non-sorted array<pointer>
ItemArray(n) -> non-sorted array<pointer>
HashArray(n) -> sorted array<hashvalue>

더하다

  1. HashArray(n) = Key.GetHash#O (1) 추가
  2. KeyArray(n) = PointerToKey#O (1) 추가
  3. ItemArray(n) = PointerToItem#O (1) 추가

없애다

  1. For i = 0 to n찾을 iHashArray(i) = Key.GetHash # O (로그 N) (정렬 된 배열)
  2. 제거 HashArray(i)# O (n) (정렬 된 배열)
  3. 제거 KeyArray(i)# O (1)
  4. 제거 ItemArray(i)# O (1)

아이템 받기

  1. For i = 0 to n찾을 iHashArray(i) = Key.GetHash# O (로그 N) (정렬 된 배열)
  2. 반환 ItemArray(i)

루프 스루

  1. For i = 0 to n, 반환 ItemArray(i)

SortedDictionary

기억

KeyArray(n) = non-sorted array<pointer>
ItemArray(n) = non-sorted array<pointer>
OrderArray(n) = sorted array<pointer>

더하다

  1. KeyArray(n) = PointerToKey#O (1) 추가
  2. ItemArray(n) = PointerToItem#O (1) 추가
  3. For i = 0 to n찾을 iKeyArray(i-1) < Key < KeyArray(i)(사용 ICompare) #의 O (N)를
  4. OrderArray(i) = n# O (n) 추가 (정렬 된 배열)

없애다

  1. For i = 0 to n, i위치 KeyArray(i).GetHash = Key.GetHash# O (n)
  2. 제거 KeyArray(SortArray(i))# O (n)
  3. 제거 ItemArray(SortArray(i))# O (n)
  4. 제거 OrderArray(i)# O (n) (정렬 된 배열)

아이템 받기

  1. For i = 0 to n, i위치 KeyArray(i).GetHash = Key.GetHash# O (n)
  2. 반환 ItemArray(i)

루프 스루

  1. For i = 0 to n, 반환 ItemArray(OrderArray(i))

SortedList

기억

KeyArray(n) = sorted array<pointer>
ItemArray(n) = sorted array<pointer>

더하다

  1. For i = 0 to n찾을 iKeyArray(i-1) < Key < KeyArray(i)(사용 ICompare) # O의 (로그 N)를
  2. KeyArray(i) = PointerToKey# O (n) 추가
  3. ItemArray(i) = PointerToItem# O (n) 추가

없애다

  1. For i = 0 to n찾을 i경우 KeyArray(i).GetHash = Key.GetHash#의 O (로그 N)
  2. 제거 KeyArray(i)# O (n)
  3. 제거 ItemArray(i)# O (n)

아이템 받기

  1. For i = 0 to n찾을 i경우 KeyArray(i).GetHash = Key.GetHash#의 O (로그 N)
  2. 반환 ItemArray(i)

루프 스루

  1. For i = 0 to n, 반환 ItemArray(i)

9
  1. 컬렉션을 반복 할 때 키별로 정렬하려는 경우. 데이터를 정렬 할 필요가없는 경우 사전 만 있으면 더 나은 성능을 얻을 수 있습니다.

  2. SortedList 및 SortedDictionary는 거의 동일한 작업을 수행하지만 구현 방식이 다르므로 여기에 설명 된 서로 다른 강점과 약점이 있습니다 .


0

@Lev가 제시 한 각 사례에 성능 점수 를 할당하려고 시도 하면서 다음 값을 사용했습니다.

  • O (1) = 3
  • O (log n) = 2
  • O (n) = 1
  • O (1) 또는 O (n) = 2
  • O (log n) 또는 O (n) = 1.5

결과는 다음과 같습니다 (높을수록 좋음).

Dictionary:       12.0 
SortedDictionary:  9.0 
SortedList:        6.5

물론 모든 사용 사례는 특정 작업에 더 많은 가중치를 부여합니다.


1
경험상 O (log n)의 가중치는 log (n) / log (2) (n이 두 배가 될 때마다 +1)이되고 O (n)의 가중치는 n이됩니다. 따라서 가중치는 최대 4 개의 크기에 대해 정확할 것입니다. 그 이상의 것은 2 : 1 비율이 빠르게 올라갈 것입니다. 예를 들어 n = 100이면 O (log n) = 15가되어야합니다. 비슷한 생각을하면 O (1)의 가중치는 100이됩니다. 결론 : O (n)은 전투를 상당히 빨리 풀어줍니다. 그렇지 않은 경우 어레이가 작다는 의미이므로 효율성이 문제가되지 않습니다.
Ama
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.