.Net 数据结构:ArrayList、List、HashTable、Dictionary、SortedList、SortedDictionary——速度、内存以及何时使用它们? [关闭]

Posted

技术标签:

【中文标题】.Net 数据结构:ArrayList、List、HashTable、Dictionary、SortedList、SortedDictionary——速度、内存以及何时使用它们? [关闭]【英文标题】:.Net Data structures: ArrayList, List, HashTable, Dictionary, SortedList, SortedDictionary -- Speed, memory, and when to use each? [closed] 【发布时间】:2010-09-12 19:40:51 【问题描述】:

.NET 有很多复杂的数据结构。不幸的是,其中一些非常相似,我并不总是确定何时使用一个以及何时使用另一个。我的大部分 C# 和 VB 书籍都在一定程度上谈到了它们,但它们从未真正深入到任何真正的细节。

Array、ArrayList、List、Hashtable、Dictionary、SortedList、SortedDictionary有什么区别?

哪些是可枚举的(IList -- 可以执行“foreach”循环)?哪些使用键/值对 (IDict)?

内存占用情况如何?插入速度?检索速度?

还有其他值得一提的数据结构吗?

我仍在寻找有关内存使用和速度(Big-O 表示法)的更多详细信息

【问题讨论】:

你应该把这个问题分开。你问了二十个不同的问题,其中一半可以通过简单的谷歌搜索来回答。请更具体;当您的问题如此分散时,它很难提供帮助。 我曾想过将其拆分,但意识到有人可能能够将所有这些答案整合到一个地方。事实上,如果有人能想出一个表格来分析所有内容,它可能会成为这个网站上的一个很好的资源。 这个问题可以转成wiki吗? Ryan,该链接上的文章已有 14 年历史(发帖时为 12 岁)。旁注我自己上周一直在阅读它们。但它们也不包括更新的技术,迫切需要更新。以及更多性能指标和示例。 LinkedList 在你的问题中有什么地方吗?只是问问。 【参考方案1】:

在我的头顶:

Array* - 代表一个老式内存数组 - 有点像普通 type[] 数组的别名。可以列举。不能自动生长。我会假设插入和检索速度非常快。

ArrayList - 自动增长的数组。增加更多开销。可以枚举,可能比普通数组慢,但仍然相当快。这些在 .NET 中被大量使用

List - 我的最爱之一 - 可以与泛型一起使用,因此您可以拥有一个强类型数组,例如List<string>。除此之外,行为很像ArrayList

Hashtable - 普通的旧哈希表。 O(1) 到 O(n) 最坏的情况。可以枚举value和keys属性,做key/val对

Dictionary - 与上面相同,只是通过泛型强类型化,例如Dictionary<string, string>

SortedList - 已排序的通用列表。插入速度变慢,因为它必须弄清楚把东西放在哪里。可以枚举。,检索时可能相同,因为它不必求助,但删除会比普通的旧列表慢。

我倾向于一直使用ListDictionary - 一旦你开始使用它们的泛型强类型,就很难再回到标准的非泛型。

还有很多其他数据结构——KeyValuePair 可以用来做一些有趣的事情,SortedDictionary 也很有用。

【讨论】:

哈希表是 O(1),最坏的情况(有冲突)可能是 O(n) 这里还有很多其他的数据结构需要添加。比如 LinkedList、Skip List、Stack、Queue、Heap、Trees、Graphs。这些也是非常重要的数据结构。 .Net 4.0 中添加的 ConcurrentDictionary 提供了具有线程安全性的通用字典 BlockingCollection 提供了一个线程安全的生产者/消费者实现 ArrayList 使用虚拟方法,但 List<T> 不使用。 ArrayList 已在很大程度上被 List<T> 替换为标准集合,Collection<T> 作为自定义集合的基类。 Hashtable 已在很大程度上被 Dictionary<TKey, TValue> 取代。对于新代码,我建议避免使用 ArrayListHashtable【参考方案2】:

如果可能,请使用泛型。这包括:

List 而不是 ArrayList 字典而不是哈希表

【讨论】:

【参考方案3】:

首先,.NET 中的所有集合都实现了 IEnumerable。

其次,很多集合都是重复的,因为泛型是在 2.0 版框架中添加的。

因此,尽管通用集合可能会添加功能,但在大多数情况下:

List 是 ArrayList 的通用实现。 Dictionary 是 Hashtable 的通用实现

数组是一个固定大小的集合,您可以更改存储在给定索引处的值。

SortedDictionary 是一个基于键排序的 IDictionary。 SortedList 是一个 IDictionary,它根据所需的 IComparer 进行排序。

因此,IDictionary 实现(那些支持 KeyValuePairs)是:

哈希表 字典 排序列表 排序字典

.NET 3.5 中添加的另一个集合是 Hashset。它是一个支持集合操作的集合。

另外,LinkedList 是一个标准的链表实现(List 是一个数组列表,可以更快地检索)。

【讨论】:

【参考方案4】:

以下是一些一般性提示:

您可以在实现IEnumerable 的类型上使用foreachIList 本质上是一个带有CountItem(使用从零开始的索引访问项目)属性的IEnumberable。另一方面,IDictionary 意味着您可以通过任何哈希索引访问项目。

ArrayArrayListList 都实现了IListDictionarySortedDictionaryHashtable 实现 IDictionary

如果您使用的是 .NET 2.0 或更高版本,建议您使用上述类型的通用对应物。

对于这些类型的各种操作的时间和空间复杂度,您应该查阅他们的文档。

.NET 数据结构位于 System.Collections 命名空间中。有一些类型库,例如 PowerCollections,它们提供了额外的数据结构。

要全面了解数据结构,请查阅 CLRS 等资源。

【讨论】:

来自msdn,似乎 sortedList 实现了 IDictionnary - 不是 IList 已修复。感谢您的评论。似乎 SortedList 保留了键/值列表,因此它基本上代表字典的数据。不记得我第一次写答案时这个类是如何工作的......【参考方案5】:

.NET 数据结构:

更多关于 ArrayList 和 List 为何不同的对话

数组

正如一位用户所说,数组是“老派”集合(是的,数组被认为是一个集合,尽管不是System.Collections 的一部分)。但是,与其他集合相比,数组的“老派”是什么,即您在标题中列出的那些(此处为 ArrayList 和 List(Of T))?让我们从数组的基础开始。

首先,Microsoft .NET 中的Arrays 是“允许您将多个 [逻辑相关] 项视为单个集合的机制”(请参阅​​链接文章)。那是什么意思?数组按顺序存储各个成员(元素),一个接一个地存储在内存中,并具有起始地址。通过使用数组,我们可以轻松访问从该地址开始按顺序存储的元素。

除此之外,与编程 101 个常见概念相反,数组确实可以非常复杂:

数组可以是单维的、多维的或jadded(jagged 数组值得一读)。数组本身不是动态的:一旦初始化,一个 n 大小的数组会保留足够的空间来容纳 n 个对象。数组中的元素数量不能增加或减少。 Dim _array As Int32() = New Int32(100) 在内存块上为数组保留足够的空间以包含 100 个 Int32 原始类型对象(在这种情况下,数组被初始化为包含 0)。该区块地址返回_array

根据文章,Common Language Specification (CLS) 要求所有数组都是从零开始的。 .NET 中的数组支持非从零开始的数组;但是,这种情况不太常见。由于从零开始的数组的“共性”,微软花费了大量时间优化其性能;因此,单维、从零开始的 (SZ) 数组是“特殊的”——并且实际上是数组的最佳实现(与多维等相反)——因为 SZ 具有用于操作它们的特定中间语言指令。

数组总是通过引用传递(作为内存地址)——这是数组难题的一个重要部分。虽然它们会进行边界检查(会引发错误),但也可以在数组上禁用边界检查。

同样,数组的最大障碍是它们不能重新调整大小。它们具有“固定”容量。将 ArrayList 和 List(Of T) 引入我们的历史:

ArrayList - 非泛型列表

ArrayList(与List(Of T) 一起——尽管有一些关键的区别,在这里,稍后解释)——也许最好被认为是集合的下一个补充(广义上)。 ArrayList 继承自IList('ICollection' 的后代)接口。 ArrayLists 本身是 bulkier - 比 Lists 需要更多 overhead。

IList 确实使实现能够将 ArrayLists 视为固定大小的列表(如 Arrays);然而,除了 ArrayLists 添加的额外功能之外,使用固定大小的 ArrayLists 并没有真正的优势,因为在这种情况下 ArrayLists(相对于 Arrays)明显更慢。

根据我的阅读,ArrayLists 不能是锯齿状的:“不支持使用多维数组作为元素......”。再一次,ArrayLists 棺材上的另一个钉子。 ArrayList 也不是“类型化的”——这意味着,在所有内容之下,ArrayList 只是一个动态的对象数组:Object[]。这在实现 ArrayList 时需要大量装箱(隐式)和拆箱(显式),再次增加了它们的开销。

未经证实的想法:我想我记得我读过或听过我的一位教授说 ArrayList 是尝试从数组转移到列表类型集合的混蛋概念孩子,即曾经数组是一个很大的改进,但它们不再是最好的选择,因为已经对集合进行了进一步的开发

List(Of T):ArrayList 变成了(并希望成为)

内存使用量的差异非常显着,以至于 List(Of Int32) 消耗的内存比包含相同原始类型的 ArrayList 少 56%(在上述绅士的链接演示中为 8 MB 与 19 MB:再次,链接 @ 987654327@) - 虽然这是 64 位机器的复合结果。这种差异确实表明了两件事:第一(1),装箱的 Int32 类型“对象”(ArrayList)比纯 Int32 原始类型(List)大得多;第二 (2),由于 64 位机器的内部工作,差异是指数级的。

那么,有什么区别,List(Of T) 是什么? MSDN 将List(Of T) 定义为“……一个可以通过索引访问的强类型对象列表”。这里的重要性是“强类型”位: List(Of T) '识别'类型并将对象存储为它们的类型。因此,Int32 存储为 Int32 而不是 Object 类型。这样就消除了装箱和拆箱带来的问题。

MSDN 指定这种差异仅在存储原始类型而不是引用类型时发挥作用。同样,这种差异确实发生在大规模:超过 500 个元素。更有趣的是,MSDN 文档中写道:“使用 List(Of T) 类的特定于类型的实现而不是使用 ArrayList 类对您有利......”

本质上,List(Of T) 是 ArrayList,但更好。它是 ArrayList 的“通用等价物”。像 ArrayList 一样,在排序之前不能保证排序(见图)。 List(Of T) 还有一些附加功能。

【讨论】:

【参考方案6】:

我对这个问题表示同情 - 我也发现(发现?)选择令人困惑,所以我开始科学地查看哪种数据结构最快(我使用 VB 进行了测试,但我想 C# 会是一样的,因为两种语言在 CLR 级别做同样的事情)。你可以看到some benchmarking results conducted by me here(还有一些关于在什么情况下最好使用哪种数据类型的讨论)。

【讨论】:

【参考方案7】:

我发现 Microsoft Docs 的集合和数据结构页面的“选择集合”部分非常有用

C# Collections and Data Structures : Choose a collection

还有下面的矩阵来比较一些其他的特性

【讨论】:

【参考方案8】:

它们在智能感知中的拼写非常好。只需输入 System.Collections.System.Collections.Generics(首选),您将获得可用内容的列表和简短说明。

【讨论】:

【参考方案9】:

哈希表/字典是 O(1) 性能,这意味着性能不是大小的函数。了解这一点很重要。

编辑:实际上,Hashtable/Dictionary 查找的平均时间复杂度为 O(1)。

【讨论】:

没有所谓的“性能”。复杂性取决于操作。例如,如果你在 Dictionary 中插入 n 个元素,由于重新散列,它不会是 O(1)。 仅供参考,即使重新散列,字典仍然是 O(1)。考虑字典扩展之前的场景。一半的元素——那些自上次扩展以来添加的元素——将被散列一次。其余的一半将被哈希两次。其余的一半,三倍,等等。对每个元素执行的平均散列操作数将是 1+1/2+1/4+1/8...=2。展开后的情况基本相同,但每个元素都被额外哈希一次(因此平均哈希计数为 3)。所有其他情况都在这两者之间。【参考方案10】:

泛型集合的性能将优于非泛型集合,尤其是在迭代多个项目时。这是因为不再发生装箱和拆箱。

【讨论】:

【参考方案11】:

关于高频系统交易工程的哈希表与字典的重要说明:线程安全问题

Hashtable 是线程安全的,可供多个线程使用。 字典公共静态成员是线程安全的,但不保证任何实例成员都是如此。

因此 Hashtable 在这方面仍然是“标准”选择。

【讨论】:

这部分是正确的。 Hashtable 可以安全地同时与一个写入器和多个读取器一起使用。另一方面,Dictionary 与多个阅读器一起使用是安全的,只要它不被同时修改。 当然。然而,在交易领域,我们同时读取实时市场数据并运行包含附加条目的分析。这还取决于有多少交易者在使用该系统 - 如果只有你,那显然没关系。 .NET 4.0 提供了一个 ConcurrentDictionary【参考方案12】:

最流行的 C# 数据结构和集合

数组 数组列表 列表 链表 字典 哈希集 堆栈 队列 排序列表

C#.NET 有很多不同的数据结构,例如,最常见的一种是数组。然而,C# 带有更多基本的数据结构。选择要使用的正确数据结构是编写结构良好且高效的程序的一部分。

在本文中,我将介绍内置的 C# 数据结构,包括 C#.NET 3.5 中引入的新数据结构。请注意,其中许多数据结构适用于其他编程语言。

数组

也许最简单和最常见的数据结构是数组。 C# 数组基本上是一个对象列表。它的定义特征是所有对象都是相同的类型(在大多数情况下)并且它们的数量是特定的。数组的性质允许根据元素在列表中的位置(也称为索引)快速访问元素。 C# 数组的定义如下:

[object type][] myArray = new [object type][number of elements]

一些例子:

 int[] myIntArray = new int[5];
 int[] myIntArray2 =  0, 1, 2, 3, 4 ;

从上面的示例中可以看出,可以不使用任何元素或从一组现有值初始化数组。将值插入数组很简单,只要它们适合。当元素的数量超过数组的大小时,该操作变得昂贵,此时需要扩展数组。这需要更长的时间,因为必须将所有现有元素复制到新的更大的数组中。

数组列表

C# 数据结构 ArrayList 是一个动态数组。这意味着 ArrayList 可以有任意数量的对象和任何类型。此数据结构旨在简化将新元素添加到数组中的过程。在底层,ArrayList 是一个数组,每次空间不足时,其大小都会翻倍。将内部数组的大小加倍是一种非常有效的策略,从长远来看可以减少元素复制的数量。我们不会在这里证明这一点。数据结构使用非常简单:

    ArrayList myArrayList = new ArrayList();
    myArrayList.Add(56);
    myArrayList.Add("String");
    myArrayList.Add(new Form());

ArrayList 数据结构的缺点是必须将检索到的值转换回其原始类型:

int arrayListValue = (int)myArrayList[0]

您可以在此处找到来源和更多信息

C# Data Structures Collections and Data Structures List vs IEnumerable vs IQueryable vs ICollection vs IDictionary System.Collections.Generic Namespace System.Collections Namespace

【讨论】:

【参考方案13】:

泛型和非泛型集合之间存在细微和不那么细微的区别。它们只是使用不同的底层数据结构。例如,Hashtable 保证一个写者多读者不同步。字典没有。

【讨论】:

以上是关于.Net 数据结构:ArrayList、List、HashTable、Dictionary、SortedList、SortedDictionary——速度、内存以及何时使用它们? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

VB.NET ArrayList 到 List(Of T) 类型的复制/转换

Set,List,Map,Vector,ArrayList的区别

c#啥时候应该使用List,啥时候应该使用arraylist?

list与arraylist 区别

转载 C#中数组ArrayList和List三者的区别

List<T>,ArrayList,IEnumerable的区别