SortedList <>,SortedDictionary <>和Dictionary <>


Answers:


101
  1. 在两个元素中的任何一个元素上进行迭代时,将对元素进行排序。并非如此Dictionary<T,V>

  2. MSDN解决了SortedList<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)对未排序的数据具有更快的插入和删除操作:O(log n)与SortedList(TKey,TValue)的O(n)相反。

如果从排序数据中一次填充列表,则SortedList(TKey,TValue)比SortedDictionary(TKey,TValue)快。


21
另一个实际的区别是,SortedList您可以按索引检索(而不是按键检索),而SortedDictionary不能。
Andrew Savinykh

65

在此处输入图片说明

我会提到字典之间的区别。

上图显示了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
Abel

21

总结性能测试的结果-SortedList与SortedDictionary与字典与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:如果您填充您的集合中的一个镜头- >去排序列表,但如果你预计你会经常需要.Add.Remove项目- >去SortedDictionary。
阿玛

也许有必要弄清楚这sorted是什么意思:当您执行a For Each MyItem in Collection而不是按照最初.Add编辑项目的顺序进行处理时,a sorted Collection将按照Key值(在中定义IComparer)的顺序对它们进行处理。例如,如果您的键是字符串,则默认情况下将按照键的字母顺序处理您的集合,但是您始终可以定义自定义排序规则。
阿玛

9
  1. 当您希望对集合进行按键排序时,对其进行迭代。如果您不需要对数据进行排序,那么最好仅使用Dictionary,它会具有更好的性能。

  2. SortedList和SortedDictionary几乎做相同的事情,但是实现方式不同,因此这里有不同的优点和缺点。


8

我可以看到建议的答案集中在性能上。下面提供的文章并未提供有关性能的任何新信息,但它解释了潜在的机制。还要注意,它不关注Collection问题中提到的三种类型,而是解决了System.Collections.Generic名称空间的所有类型。

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

提取物:

字典<>

字典可能是最常用的关联容器类。字典是关联查找/插入/删除最快的类,因为它在底下使用哈希表。因为键是散列的,所以键类型应正确地正确实现GetHashCode()和Equals(),或者在构造时应为字典提供外部IEqualityComparer。字典中项目的插入/删除/查找时间是摊销的恒定时间-O(1)-这意味着,不管字典有多大,查找某物所花费的时间都保持相对恒定。这对于高速查找是非常理想的。唯一的缺点是,根据使用哈希表的性质,字典是无序的,因此您无法轻松地依次遍历字典中的项目

SortedDictionary <>

SortedDictionary在用法上类似于Dictionary,但在实现上有很大不同。该SortedDictionary底层使用二叉树通过钥匙来维持秩序中的项目。排序的结果是,用于键的类型必须正确实现IComparable,以便可以正确地对键进行排序。排序后的字典需要一些查找时间,才能维护项目的顺序,因此排序字典中的插入/删除/查找时间是对数-O(log n)。一般而言,使用对数时间,您可以将集合的大小增加一倍,并且只需执行一次额外的比较即可找到该项目。当您想要快速查找但又希望能够通过键来维护集合时,请使用SortedDictionary。

SortedList <>

SortedList是通用容器中的另一个已排序的关联容器类。与SortedDictionary一样,SortedList再次使用键对键值对进行排序。但是,与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,在i哪里找到HashArray(i) = Key.GetHash #O(log n)的(排序的数组)
  2. 去掉 HashArray(i)#O(n)(排序数组)
  3. 去掉 KeyArray(i)#O(1)
  4. 删除ItemArray(i)#O(1)

获取物品

  1. For i = 0 to n,在i哪里找到HashArray(i) = Key.GetHash#O(log n)的(排序的数组)
  2. 返回 ItemArray(i)

依次通过

  1. For i = 0 to n,返回 ItemArray(i)

分类词典

记忆

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,找到i位置KeyArray(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,找到i位置KeyArray(i-1) < Key < KeyArray(i)(使用ICompare)#O(log 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(log n)
  2. 删除KeyArray(i)#O(n)
  3. 删除ItemArray(i)#O(n)

获取物品

  1. For i = 0 to n,找到#O(log n)i在哪里KeyArray(i).GetHash = Key.GetHash
  2. 返回 ItemArray(i)

依次通过

  1. For i = 0 to n,返回 ItemArray(i)

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.