【问题标题】:Default Capacity of List列表默认容量
【发布时间】:2009-11-19 11:59:03
【问题描述】:

List 的默认容量是多少?

【问题讨论】:

标签: c# .net list capacity


【解决方案1】:

其实它是从容量0开始的。当你添加第一个元素时,当前实现分配容量为4。之后,如果需要扩展,容量会保持加倍,以保证摊销O(1)操作。

请记住,这是当前行为。你不应该依赖它。这应该展示当前的行为:

List<int> list = new List<int>();
int capacity = list.Capacity;
Console.WriteLine("Capacity: " + capacity);

for (int i = 0; i < 100000; i++)
{
    list.Add(i);
    if (list.Capacity > capacity)
    {
        capacity = list.Capacity;
        Console.WriteLine("Capacity: " + capacity);
    }
}

【讨论】:

  • 您能否详细说明“保证摊销 O(1) 操作”的含义?
  • 基本上是意味着不管你需要多少容量..越多
  • @DavidKlempfner 如果您每次都将容量翻倍,您将为大约2n 项目(包括过去的分配)分配空间 - 所以因为这是给n .Adds,所以它出来了每个.Add 大约2 任意时间单位,又名摊销O(1) 时间。 (当然,这假设分配需要线性时间)
【解决方案2】:

你为什么不试试呢?

Console.WriteLine("Default capacity of a List: " + new List<int>().Capacity);

此答案适用于所有具有列表的 .NET 版本。在我的版本中,它恰好是 0。

【讨论】:

  • “你为什么不试试看?” question 使问题处于负面状态,恕我直言,这是一个错误。即使是出于文档目的“容易尝试”的事情,这里也应该存在问题。
【解决方案3】:

根据MSDN parameterless constructor documentation上的示例,创建的列表的初始容量为:

List<string> x = new List<string>();

为 0。据我所知,这没有记录为保证,也没有记录调整大小策略(即,它目前可能会翻倍,至少 4,但在 .NET 5.0 中,它可能会增加三倍至少 128。)基本上,你不应该依赖这种行为。

【讨论】:

  • 实际上它声明它“是空的并且具有默认的初始容量”。使用反射器默认显示为 4。
  • @Brian:不,在这种情况下,默认初始容量为 0。 4 是必须包含元素的列表的第一个容量。重要的是它没有记录为 0 或 4。在下一个版本中它可能是 100,而不会破坏任何记录的行为。
  • @Brian:无论文档说什么,根据Capacity 属性,它都是从 0 开始的。
  • @Jon:我完全同意这是一个实现细节,这是这里的重点。我明白你的意思。 4 是实际添加到列表中的“默认容量”。
【解决方案4】:

List 的默认容量是 4 项(插入初始项后,否则为 0 大小)

var list = new List<int>();
list.Add(1);

Assert.AreEqual(4, list.Capacity);

【讨论】:

  • 是的,它是这样呈指数增长的,4、8、16、32、64……但默认绝对是 0。
  • 请注意,它会不断将初始容量加倍,不一定是 2 的幂。如果初始容量为 3,那么您将得到 3、6、12、24 等。
  • 所以默认容量是0,而不是4。按照您的逻辑,“默认”容量是 100 万(在插入几千个项目之后)。
【解决方案5】:

容量默认为0,但如果您创建一个空白列表[List1],如下所示。如果您创建的列表在 [List2] 中有如下元素,则您添加的元素数量变为 N 超过 2。默认容量会有所不同。

List<int> List1 = new List<int>(); //count=0, capacity=0
List<int> List2 = new List<int>(){ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; //count=11, capacity=16

Array类型的元素被添加后,开发者使用ReSize方法扩展了数组。它工作得非常缓慢。在开发List类型的同时,容量也得到了一定的提升。该比率已发展为 N 大于 2。

如果添加到列表中的成员数量超过了,则当前容量会增加一倍。 如果您从列表中删除某些值,容量不会减少。容量只会增加,不会减少。即使是 Clear 方法也不影响它。

【讨论】:

    【解决方案6】:

    如果您大致知道要在列表(或堆栈或队列)中存储多少项目,则应使用容量。

    在这种情况下,您将避免内存复制。发生内存复制是因为在底层列表(堆栈和队列)依赖数组来存储它们的项目。该数组大小是您的容量,但它与列表大小不同。由于列表的大小需要大于数组的大小,List 实现将分配一个更大的数组(因子 2 可能更小),并将所有项从旧数组复制到新数组以及新添加的项。

    因此,如果您知道列表中可能有 50 到 60 个项目,请创建一个容量为 60 的列表,并且不会发生内存释放。

    注意:看起来垃圾收集器不必清理旧数组

    【讨论】:

      【解决方案7】:

      这一切都在于确保容量能够存储另一个元素:

      int num = this._items.Length == 0 ? 4 : this._items.Length * 2;
      

      从 mscorlib 4.0.0.0 deassebled 得到这个 - 当然,正如 Jon 所说,这不能保证将来不会改变(到目前为止它仍然保持在 0、4、8、16...)。

      当然,你可以自己设置,这样可以是 3、9、27 等。

      【讨论】:

      • 你的意思是 3、6、12 等等。(它总是加倍,从提供的初始容量开始。)
      • @yoyo,我认为当 tomkuj 说“当然,您可以自己设置,因此可以是 3、9、27 等。”这只是演示了一些可以在 List 初始化中选择作为容量值的任意随机数,而不是演示加倍。
      猜你喜欢
      • 1970-01-01
      • 2012-08-29
      • 2012-02-22
      • 2010-12-12
      • 2020-09-10
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多