可以快速调整大小的数组

Posted

技术标签:

【中文标题】可以快速调整大小的数组【英文标题】:Array that can be resized fast 【发布时间】:2010-09-29 15:24:20 【问题描述】:

我正在寻找一种可以轻松添加项目且不会影响性能的数组数据类型。

System.Array - Redim Preserve 将整个 RAM 从旧的复制到新的,与现有元素的数量一样慢 System.Collections.ArrayList - 够好吗? System.Collections.IList - 够好吗?

【问题讨论】:

IList 只是一个接口,因此没有具体的实现。 【参考方案1】:

您应该为此使用通用列表 (System.Collections.Generic.List)。它在constant amortized time 运行。

它还与数组共享以下功能。

快速随机访问(您可以在 O(1) 中访问列表中的任何元素) 循环很快 在开头或中间插入和删除对象很慢(因为它必须复制整个列表相信)

如果您需要在开头或结尾快速插入和删除,请使用链表或队列

【讨论】:

或者在开头使用预期的项目数对其进行初始化。 这是迂腐的,但我会争论“它会自动调整自身大小并保持不变的摊销时间”这句话的适当性。添加和删​​除是不断摊销的(这就是我假设你的意思);实际调整大小不是。 也许有点迂腐,但我会改变措辞。 :)【参考方案2】:

LinkedList 结构对你有用吗?它(在某些情况下)不像直接数组那样直观,但非常快。

AddLast 追加到末尾 AddBefore/AddAfter 插入到列表中 AddFirst 追加到开头

但是,随机访问并不是那么快,因为您必须遍历结构才能访问您的项目...但是,它具有 .ToList() 和 .ToArray() 方法来获取列表中结构的副本/array 形式,因此对于读取访问,您可以在紧要关头做到这一点。插入的性能提高可能超过随机访问需求的性能降低,也可能不会。这完全取决于您的情况。

还有一份参考资料可以帮助您确定正确的方法:

When to use a linked list over an array/array list?

【讨论】:

【参考方案3】:

简单总结几个数据结构:

System.Collections.ArrayList:无类型数据结构已过时。请改用 List(of t)。

System.Collections.Generic.List(of t):这表示一个可调整大小的数组。这个数据结构在幕后使用了一个内部数组。只要底层数组没有被填充,将项目添加到 List 是 O(1),否则它是 O(n+1) 来调整内部数组的大小并复制元素。

List<int> nums = new List<int>(3); // creates a resizable array
                                   // which can hold 3 elements

nums.Add(1);
// adds item in O(1). nums.Capacity = 3, nums.Count = 1

nums.Add(2);
// adds item in O(1). nums.Capacity = 3, nums.Count = 3

nums.Add(3);
// adds item in O(1). nums.Capacity = 3, nums.Count = 3

nums.Add(4);
// adds item in O(n). Lists doubles the size of our internal array, so
// nums.Capacity = 6, nums.count = 4

添加项目仅在添加到列表末尾时才有效。在中间插入会强制数组将所有项目向前移动,这是一个 O(n) 操作。删除项目也是 O(n),因为数组需要向后移动项目。

System.Collections.Generic.LinkedList(of t):如果您不需要对列表中的项目进行随机或索引访问,例如,您只计划添加项目并从头开始迭代最后,LinkedList 是你的朋友。插入和删除是 O(1),查找是 O(n)。

【讨论】:

次要的,小问题 - 我认为没有 O(n+1) 这样的事情。大 O 表示法确实有一个数学定义,但即使是非正式的,它的目的也是为了显示算法的数量级。正如 O(n^2 + 400n + 5) 无论系数如何都是 O(n^2),O(n+1) 也是 O(n)。【参考方案4】:

什么对你来说“足够好”?你到底想用那个数据结构做什么?

没有数组结构(即 O(n) 访问)允许在没有 O(n) 运行时的情况下插入中间;最后的插入是 O(n) 最坏的情况,对于像 ArrayList 这样的自调整大小的数组,需要 O(1) 摊销。

也许哈希表(分摊 O(1) 访问和插入任何地方,但 O(n) 最坏情况插入)或树(O(log(n)) 任何地方访问和插入,保证)更适合。

【讨论】:

【参考方案5】:

如果速度是您的问题,我看不出所选答案比使用原始数组有什么好处,尽管它会自行调整大小,但它使用与调整数组大小完全相同的机制(并且应该只需稍长一点)除非你总是添加到最后,在这种情况下它应该做的事情更聪明一些,因为它一次分配一个块而不是一个元素。

如果您经常在集合的开头/中间添加,并且不经常索引到中间/结尾,您可能需要链接列表。这将具有最快的插入时间并且将有很长的迭代时间,它只是在索引方面很糟糕(例如从末尾开始查看第 3 个元素或第 72 个元素)。

【讨论】:

以上是关于可以快速调整大小的数组的主要内容,如果未能解决你的问题,请参考以下文章

如何简单快速地调整图片大小

为啥我的动态数组可以在不调整大小的情况下工作? [复制]

UIWebView 调整大小缓慢

在 PowerShell 中调整字节数组图像的大小

算法(第四版)学习笔记之java实现可以动态调整数组大小的栈

C# 数据结构,可以动态调整大小到给定限制的列表,并允许快速访问任何索引