我可以帮你翻译成中文:我在哪里可以学习不同类型的.NET列表?

29

有没有什么好的资源可以简明地解释C#中可用的不同类型的列表及其适当使用时机?

例如,List、Hashtable、Dictionaries等。

我从来不确定何时应该使用什么。

10个回答

32

这些不是所有的列表,但它们都是集合。以下是一个快速概述。

非泛型集合(API以object为单位。值类型被装箱。

这些主要在System.Collections命名空间中:

  • ArrayList:由数组支持的项目列表。快速随机读/写访问。如果缓冲区不需要调整大小,则尾端添加很快。
  • Hashtable:从键到值的映射。键是唯一的,值不必是唯一的。使用GetHashCode方法实现接近O(1)的读/写访问(除了所有项具有相同哈希或后备存储器需要重建的恶劣情况)。遍历键/值对会给出一个不可预测的顺序。(好吧,实际上是不可预测的。)
  • SortedList:类似于Hashtable,但条目始终按键排序返回。存储为键/值对列表。
  • Stack:后进先出集合
  • Queue:先进先出集合
  • Array:固定大小的O(1)随机访问;非泛型,但也有强类型形式

泛型集合。 (强类型API,不会装箱值类型(假设适当的T)。

这些主要在System.Collections.Generic命名空间中

可能最重要的集合接口IEnumerable(和IEnumerable<T>)。它代表了一个项目序列,就像Stream代表了一系列字节一样。没有随机访问,只有向前读取。LINQ to Objects基于此,并且几乎所有集合类型都实现了它。


1
还有更多好用的 System.Collections.Specialized - 例如 StringDictionary 和 NameValueCollection。 - Hafthor
@Hafthor:是的,虽然大多数已经随着泛型的出现而有些过时了。 - Jon Skeet
3
您整理的 List<Collection Types> 很棒,里面包含我所使用过的所有内容。 - stephenbayer

8
为了进一步解释tobsen之前的答案,C5通用集合库有许多集合。以下是其中一些:
队列/栈
- `CircularQueue`:该类提供严格的队列和栈功能。同时,可以使用索引器以cq[0](其中0是最旧的项目,下一个要出队,最后弹出)以O(1)的效率访问Stack / Queue中的任何项。
列表
注意:`ArrayList`和`LinkedList`也可以作为队列/栈使用
- `ArrayList`:与其在`System.Collections.Generic(SCG)`中对应的`List`类似,这是由数组支持的,保证O(1)的索引,但最坏情况下需要O(n)的插入。O(n)查找项。 - `LinkedList`:与其对应的`SCG.LinkedList`类似。使用双向链表,保证O(1)的插入,但最坏情况下需要O(n)的索引(实际上与列表的头或尾的距离成比例)。还需要O(n)来查找项。排序使用稳定的Merge Sort。 - `HashedArrayList`:类似于上面的`ArrayList`,但不允许重复。您得到的好处是找到项及其索引的时间缩短为O(1)。 - `HashedLinkedList`:类似于上面的`LinkedList`,但不允许重复。与之前一样,找到项的时间缩短为O(1),但查找其索引的时间仍为O(n)。 - `WrappedArray`:与`ArrayList`非常相似,它作为一个围绕实现了"C5.IList"的数组的包装器,但是如果尝试修改集合,则会抛出异常(`IsFixedSize`为true,并且`Add`,`Remove`,`Insert`无效;`Sort`,`Shuffle`,和`Reverse`有效,因为它们是就地操作)。
列表还提供了“视图”功能,它表示基础列表的一部分,允许执行本地操作。使用C5书中提供的模式,可以使用对数组和链表都有效的视图执行操作。任何列表操作也可以在视图上执行,将其效果限制为基础列表的子集。
排序集合:
- SortedArray:类似于ArrayList,但它保持其项目已排序并且不允许重复项。请注意,此集合上的随机插入和删除较慢。如果项目数很少或很少修改但经常按项索引或值访问,则此集合最佳。 - TreeSet:使用红黑树结构来保持项目排序。作为一个集合,它不允许重复项。按索引或项值访问以及插入/删除需要O(log n)时间。 - TreeBag:使用红黑树,保持项目排序。作为一个bag,它允许重复项,但不会在树中存储重复项,而是通过计数来保留重复项。
TreeSet和TreeBag都提供了在O(1)时间内高效地创建“快照”或持久性副本的能力,允许在修改基础树的同时迭代快照。请注意,每个树上的快照都会对更新树的性能产生影响,但是当快照被处理时,这些影响会消失。
哈希集合:
- HashSet:使用简单的哈希表进行存储。按项值访问需要O(1)时间。作为一个集合,它不允许重复项。提供了一个函数BucketCostDistribution(),可以帮助您确定项的哈希码函数的效率。 - HashBag:类似于HashSet,但具有bag语义,这意味着允许重复项,但仅通过计数存储重复项。
优先队列:
- IntervalHeap:提供了一个优先队列。查找最大和最小值是O(1)操作,删除最大值、最小值、添加和更新是O(log n)操作。通过显式存储它们(而不是通过计数)来允许重复项。
字典:
  • HashDictionary<H,K>: 类似于SCG.Dictionary<H,K>,提供O(1)的条目访问、插入和删除。还提供一个BucketCostDistribution()函数,与上面的HashSet<T>相同。不保证任何特定的枚举顺序。
  • TreeDictionary<H,K>: 类似于SCG.SortedDictionary<H,K>,使用红黑树提供持久排序的字典。 条目访问、插入和删除需要O(log n)。 保证字典的枚举遵循键比较器指定的顺序。

Guarded Collections

此外,C5还提供了“guarded”集合,它有效地充当只读包装器,防止修改集合。 集合中的项目仍然可以被修改,但是不能向集合中添加、删除或插入项目。

这是关于C5库各种集合的详细答案。我发现C5库非常好用,经常在自己的代码中使用,将常见的C#头文件替换为:

using C5;
using SCG = System.Collections.Generic;

6
你应该选择一本关于基本数据结构的书籍。无论使用哪种语言,它都是相同的理论。
简短解释:
- Array:(例如 int[] myArray)静态数组,当集合永远不会改变时可以使用它(您无法在其中添加或删除项目,但可以更改单个项目的值) - ArrayList:通用的数组/列表,允许相对快速地枚举和直接访问。此列表可以自动增长,因为您添加项目,但由于它只存储 Object,所以由于性能和类型安全问题,您应该很少使用它。 - List:上述 ArrayList 的泛型版本。它在性能和灵活性之间提供了良好的平衡,并且在具有动态平面列表项时几乎始终应使用它。(.NET 2.0 中新增) - Hashtable:类似于平面列表,但不是使用整数进行索引,而是可以使用任何对象进行索引。值得注意的是,哈希表中没有“顺序”。 - Dictionary:Hashtable 的泛型版本。出于与上面的 ArrayList vs List 相同的原因,在 .NET 2.0 及更高版本中使用它而不是 Hashtable。 - Stack:提供后进先出类型的列表。您最后添加的项目将是您在挑选东西时首先收到的项目。 - Queue:提供先进先出列表。将其视为一个管道,在其中一个端口插入项目并在另一个端口挑选它们。通常用于在线程之间传递消息。
一般来说,您应该在 .NET 2.0 及更高版本中几乎使用泛型集合进行所有操作。与 ArrayList 和 HashTable 相比,您将获得完全的类型安全性,并且对于值类型(整数、结构体、浮点数等),它们比非泛型的速度要快得多。
如果您有一个永远不会改变的项目列表,或者您不需要/想要 List 的灵活性,当然可以使用数组,因为它具有最少的开销。
当您从公共方法或属性返回集合时,建议将其转换为较不灵活的接口。因此,如果您返回一个 List,则可以将其转换为 IEnumerable,这意味着您的用户无法添加项目(除非当然它再次转换,但仍然是对用户的指示)。将其强制转换还将为您提供更改底层数据结构的灵活性,同时保持 API 的稳定性。您还可以选择 ICollection 或 IList 来公开一些更多功能,但保持实际数据结构隐藏。

这是一个不错的列表 =D 顺便问一下,你能否添加 SortedListSortedDictionary,因为它们通常是真正令人困惑的(即使在JonSkeet的回答之后)。 - Pacerier

5

哈希表

  • 字典(Dictionary)
  • 哈希表(非泛型)(Hashtable)

哈希表是一种数据结构,它允许您保留键值对。给定一个有序的键,您可以插入一个值。一个简单的例子可能是学生列表,其中键是学生ID,而值是学生姓名。

随机访问列表

  • 列表(List)
  • 动态数组(非泛型)(ArrayList)

随机访问列表用于存储要随机访问的大量对象(即,您想在O(1)时间内访问第n个元素)。如果您想在列表中间插入/删除元素,则不好,因为这将需要整个列表进行重排,这可能需要一些时间。

链表及其类似物

  • 链表(LinkedList)
  • 队列(Queue)
  • 栈(Stack)

如果您不想在中间访问元素,则链表很棒,因为这需要O(N)时间。如果您想在中间插入/删除元素,则很棒,因为它只涉及更改一些指针。

队列和栈略微专业化,因为它们针对FIFO和FILO行为进行了优化(分别是先进先出和后进先出)。


哈希表不也是一种随机访问列表吗? - Pacerier

2
如果你从System.Collections的MSDN文档开始,你可以深入了解各个集合类型的细节以及如何使用它们。例如,Hashtable的文档说,“表示基于键的哈希码组织的键/值对集合。”
此外,在理解泛型中也有关于System.Collections.Generic的良好讨论。

2

List<T>是可排序的,但不建议公开使用。

Collection<T>是基本的、无花俏的集合。

Dictionary<T>是一组键值对的集合(类似于旧的哈希表,但现在是通用的)。

KeyedCollection<T>是一个字典,其中可以从值确定键(这是一个抽象类,因此您必须继承它并支持GetKey函数)

ReadOnlyCollection<T>是一种特殊的集合,其中内容不能被修改。

ArrayList和HashTable从 .NET 2.0 开始基本上已经过时了。


你有一个建议过时的链接吗? - Pacerier

2
除了迄今为止的众多回答外,C5通用集合库还提供了更多的集合。在根据您的要求决定使用什么时,他们网站上的文档(也可获得)可能会有所帮助。

1

MSDN有一篇名为选择集合类的文章,我在尝试确定何种集合类适用于特定情况时,发现它非常有用。


0
这些是各种类型的 通用数据结构 示例。这些数据结构在软件工程中随处可见。

-3

如果您在代码窗口中键入System.collections.Generic.,Intellisense将为您显示每个的简短描述。不要忘记末尾的句号。还有System.Collections.ObjectModel.。从那里,您应该能够从MSDN获取更多有关看起来很有前途的任何内容的信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接