.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
- 已排序的通用列表。插入速度变慢,因为它必须弄清楚把东西放在哪里。可以枚举。,检索时可能相同,因为它不必求助,但删除会比普通的旧列表慢。
我倾向于一直使用List
和Dictionary
- 一旦你开始使用它们的泛型强类型,就很难再回到标准的非泛型。
还有很多其他数据结构——KeyValuePair
可以用来做一些有趣的事情,SortedDictionary
也很有用。
【讨论】:
哈希表是 O(1),最坏的情况(有冲突)可能是 O(n) 这里还有很多其他的数据结构需要添加。比如 LinkedList、Skip List、Stack、Queue、Heap、Trees、Graphs。这些也是非常重要的数据结构。 .Net 4.0 中添加的 ConcurrentDictionary 提供了具有线程安全性的通用字典 BlockingCollectionArrayList
使用虚拟方法,但 List<T>
不使用。 ArrayList
已在很大程度上被 List<T>
替换为标准集合,Collection<T>
作为自定义集合的基类。 Hashtable
已在很大程度上被 Dictionary<TKey, TValue>
取代。对于新代码,我建议避免使用 ArrayList
和 Hashtable
。【参考方案2】:
如果可能,请使用泛型。这包括:
List 而不是 ArrayList 字典而不是哈希表【讨论】:
【参考方案3】:首先,.NET 中的所有集合都实现了 IEnumerable。
其次,很多集合都是重复的,因为泛型是在 2.0 版框架中添加的。
因此,尽管通用集合可能会添加功能,但在大多数情况下:
List 是 ArrayList 的通用实现。 Dictionary数组是一个固定大小的集合,您可以更改存储在给定索引处的值。
SortedDictionary 是一个基于键排序的 IDictionary
因此,IDictionary 实现(那些支持 KeyValuePairs)是:
哈希表 字典.NET 3.5 中添加的另一个集合是 Hashset。它是一个支持集合操作的集合。
另外,LinkedList 是一个标准的链表实现(List 是一个数组列表,可以更快地检索)。
【讨论】:
【参考方案4】:以下是一些一般性提示:
您可以在实现IEnumerable
的类型上使用foreach
。 IList
本质上是一个带有Count
和Item
(使用从零开始的索引访问项目)属性的IEnumberable
。另一方面,IDictionary
意味着您可以通过任何哈希索引访问项目。
Array
、ArrayList
和 List
都实现了IList
。
Dictionary
、SortedDictionary
和 Hashtable
实现 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最流行的 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的区别