使用什么数据结构来实现arraylist

时间:2012-06-30 14:53:11

标签: c# data-structures arraylist

在构建arraylist时使用了什么数据结构,因为我们可以在其上动态添加/删除值。

我假设它使用链接列表,但在做了一些谷歌后,我发现它使用了矢量..但没有更多关于它的细节。

5 个答案:

答案 0 :(得分:14)

在现代处理器上,内存缓存是王道。有效地使用缓存会产生巨大的差异,当程序访问内容未缓存的地址时,处理器很容易被停顿数百个周期,等待非常慢的内存总线提供数据。

按顺序访问内存时,访问内存效率最高。一个字节在缓存中可用的几率是最大的,它很可能出现在同一缓存行中。假设您按顺序索引数组元素,这使得数组成为最有效的集合对象。

因此,除LinkedList之外的所有.NET集合类都使用数组来存储数据。包括散列集合(Hashtable,Dictionary,Hashset),它们使用数组数组。包括ArrayList。应该避免使用LinkedList,因为它的缓存局部性很差,除非在随机已知位置进行廉价的插入和删除是主要问题。

数组的一个问题是它们的大小是固定的,这使得很难实现自动调整大小的集合,比如ArrayList。这是通过故意浪费地址空间来解决的。每当阵列填满容量时,阵列将重新分配并复制元素。重新分配是以前大小的两倍,您可以从Capacity属性中观察到这一点。虽然这个听起来很昂贵,但算法是分摊的O(1),并且操作系统中的虚拟内存子系统确保您实际上不会为不使用的内存付费。

您可以通过预先猜测容量来避免不那么便宜的复制。有关this answer中的详细信息。

答案 1 :(得分:2)

Arraylist在内部使用数组来存储数据,并在需要时调整数组大小。

Arraylist的java实现在内部创建一个具有初始大小的数组,并调整数组的大小。

您可以在此处查看实施: http://www.docjar.com/html/api/java/util/ArrayList.java.html

这适用于Java,但.NET的概念相同。

答案 2 :(得分:1)

来自MSDN page

  

使用一个数组实现IList接口,该数组的大小根据需要动态增加。

直接使用类而不是数组的一些的好处是:

  • 可以在IList
  • 的任何地方使用
  • 它在从数组中间添加/删除项目时为您处理调整大小和复制
  • 它会跟踪数组中的“最后”项目
  • 它提供了二进制搜索数组中项目的方法

答案 3 :(得分:1)

ArrayList在内部将值存储为对象数组,并公开一些公共帮助程序方法,以便更容易地使用数组(通过IList接口公开)。

插入项目时,插入点右侧的所有元素都会向右移动,从而使插入效率低下。另一方面,追加是快速的,因为不需要移位元素(除非内部数组已达到容量,在这种情况下,它将被更大的数组替换)。

因为这些值在内部存储为数组,所以它提供了数组的优点(例如,如果对值进行排序,则进行高效搜索)。

答案 4 :(得分:1)

见这里:ArrayList source

如前所述,它是一个数组。

private object[] _items;

这是Add()方法:

public virtual int Add(object value)
{
    if (this._size == this._items.Length)
    {
        this.EnsureCapacity(this._size + 1);
    }
    this._items[this._size] = value;
    ArrayList expr_2D = this;
    ArrayList arg_2E_0 = expr_2D;
    expr_2D._version = arg_2E_0._version + 1;
    ArrayList expr_3B = this;
    ArrayList arg_3C_0 = expr_3B;
    ArrayList arg_45_0 = expr_3B;
    int expr_41 = arg_3C_0._size;
    int arg_42_0 = expr_41;
    int arg_44_0 = expr_41;
    int i = arg_42_0;
    arg_45_0._size = arg_44_0 + 1;
    return i;
}

如您所见,调用EnsureCapacity ...最终调用set_Capacity:

public virtual void set_Capacity(int value)
{
    if (value < this._size)
    {
        throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
    }
    if (value != this._items.Length)
    {
        if (value <= 0)
        {
            this._items = new object[4];
            goto IL_65;
        }
        object[] array = new object[value];
        if (this._size > 0)
        {
            Array.Copy(this._items, 0, array, 0, this._size);
        }
        this._items = array;
        return;
    }
    IL_65:
}

如果需要增加容量,整个阵列将被复制到更大的阵列。