List <t>中使用哪种算法来动态分配内存?</t>

时间:2013-02-16 18:28:08

标签: c# .net arrays algorithm data-structures

现在我有一个动态分配数组内存的算法:

  • 如果数组已满,我会创建一个大小为两倍的新数组,并复制项目。
  • 如果数组是四分之一满,我创建一个大小一半的新数组,并复制项目。

这是用于动态内存分配的相当快的算法,尽管将元素复制到新分配的数组有额外的开销。

  1. 什么是基于数组的更快,List<T>或这样的算法?你会建议使用什么?

  2. List<T>是否使用简单数组作为内部数据结构?

6 个答案:

答案 0 :(得分:9)

回答你的问题:

确实,C#的List<T>实现使用了一个

的内部数组
  1. 序列化
  2. 线程安全
  3. 实现IEnumerable<T>(这意味着它可以是LINQ查询,foreach等等)
  4. 二进制搜索
  5. 等等

    因此,我会要求您使用List<T>而不是您自己的列表。

    哦,顺便说一下,如果你想要来自微软的List<T>源代码,那么它就是

    List.cs

    修改

    EnsureCapacityList<T>的源代码是:

        // Ensures that the capacity of this list is at least the given minimum
        // value. If the currect capacity of the list is less than min, the
        // capacity is increased to twice the current capacity or to min,
        // whichever is larger.
        private void EnsureCapacity(int min) {
            if (_items.Length < min) {
                int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2;
                if (newCapacity < min) newCapacity = min;
                Capacity = newCapacity;
            }
        }
    

答案 1 :(得分:6)

除非您有特别的理由相信,否则使用C#附带提供的库几乎是一个好主意。这些实现已经很好地实现,经过良好调试,并且经过了充分测试。

您描述的数据结构是动态数组数据结构的标准实现,大多数语言都将此作为默认列表实现。查看the documentation for List<T>,似乎List<T>使用此实现,因为其文档引用了内部容量,并且只要大小小于容量,就保证O(1)追加。

简而言之,除非必须,否则请避免重新发明轮子。

希望这有帮助!

答案 2 :(得分:4)

List<T>在内部使用数组,它使用与您类似的策略 - 如果长度超过数组的长度,它会使数组的大小加倍。但是,如果尺寸变小,它就不会变小。

mscorlib中的相关方法:

private void EnsureCapacity(int min)
{
    if (this._items.Length < min)
    {
        int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2);
        if (num < min)
        {
            num = min;
        }
        this.Capacity = num;
    }
}

数组的大小调整实际上发生在List<T>.Capacity的设置器中。

答案 3 :(得分:2)

是的,List<T>在内部使用T[]来保存您的对象。

据我记得.NET 4.0源代码,在添加新对象之前,它确保数组有足够的容量来容纳新的对象数。如果现有数组不能容纳新数量的对象,则将其替换为大小加倍的新数组,并将所有对象和所有现有引用复制到新数组。

答案 4 :(得分:2)

无需重新发明轮子。

来自MSDN:

  

容量是List&lt;(Of&lt;(T&gt;)&gt;)可以存储的元素数量   在需要调整大小之前,Count是元素的数量   它实际上在List&lt;(Of&lt;(T&gt;)&gt;)中。

     

容量始终大于或等于Count。如果计数超过   添加元素时的容量,容量增加了   在复制旧数据之前自动重新分配内部数组   元素和添加新元素。

     

可以通过调用TrimExcess方法或通过调用容量来减少容量   显式设置Capacity属性。当Capacity的值   显式设置,内部数组也重新分配   容纳指定的容量,并复制所有元素。

     

检索此属性的值是O(1)操作;设置   该属性是O(n)操作,其中n是新容量。

答案 5 :(得分:0)

那是基本上 List<T>(以及许多其他语言的动态数组)也是如此。调整大小的因素可能会有所不同,我认为在删除元素时它不会自行缩小支持数组 - 但是TrimToSize你可以自己设置Capacity,如果客户端代码很好地使用此功能,则可能允许更有效的策略。但基本上,它是渐近等价的。

至于使用哪一个:除非你有List<T>对你的用例来说不是最理想的冷,硬数据,并且差异很重要(你显然还没有这方面的知识),你应该使用它。您自己的实现将是错误的,功能较少(参见IEnumerable<T>IList<T>,众多方法),不太优化,不太广泛可识别,不被其他库接受(因此您可能需要创建昂贵的复制,或者至少做比List<T>更多的工作更多的工作)等等,而且很可能绝对没有任何东西可以获得。