【问题标题】:"I i can traverse a list using indexing as i do in an array.Why can't i add an item in a list as i do in an array using indexing."“我可以像在数组中一样使用索引遍历列表。为什么我不能像在使用索引的数组中那样在列表中添加项目。”
【发布时间】:2019-08-01 14:17:22
【问题描述】:

为什么我需要使用Add()List 添加元素。为什么我不能使用索引并做到这一点。当我通过List 遍历元素时,我使用索引的帮助。

int head = -1;
List<char> arr = new List<char>();
public void push(char s)
{
    ++head;
    arr[head] = s;//throws runtime error.
    arr.Add(s);
}

它在编译期间不会抛出任何错误。但是在运行时抛出一个错误,声明IndexOutOfRangeException

【问题讨论】:

  • @AFriend 设置容量并不一定意味着列表将在该索引处包含项目,只是列表在超过所述容量之前不需要内部扩展。
  • 您可能正在寻找Queue&lt;char&gt;Stack&lt;char&gt;

标签: c# data-structures


【解决方案1】:
++head; 
arr[head] = s;

这会尝试将列表的元素 1 设置为 s,但是还没有元素 1,因为您没有添加任何内容,或者设置了列表的长度。

当你创建一个数组时,你定义了一个长度,所以每个项目都有一个可以分配的内存地址。

当您不知道要拥有多少项目或它们的索引将是什么时,列表很有用。

【讨论】:

  • 所以当我像这样在列表中遍历“arr[i]”时,这意味着这是列表中的第一个元素,而在数组中则意味着在内存位置 arr[i ],这是元素??请解开我的疑惑
  • 当您通过索引访问项目时,数组和列表的工作方式相同。它们都是指向内存地址的指针列表。
  • 这是否也意味着列表也将数据存储在连续的内存块中??
  • 我对此表示怀疑,C# 并没有公开它的内存管理,但是如果您添加和删除内容,它必然会变得支离破碎。即使是对象数组,指针列表也可能是连续的,但这些指针可以指向任何地方。
【解决方案2】:

数组是固定大小的。一旦分配了它们,就不能从中添加或删除“插槽”。因此,如果您需要更大,您需要:

  1. 检测到您需要更大的阵列。
  2. 分配一个新的更大的数组
  3. 将所有现有值复制到新的更大的数组中
  4. 从现在开始到处使用更大的数组

Lists 所做的只是自动化这个精确的过程。它会在 Add() 期间自动检测到它需要增加,然后自动执行步骤 2-4。它甚至负责选择初始大小以及增长多少(以避免不得不经常增长。

理论上,他们可以通过将大小增加到 11000 来对 List[11000] 做出反应。但是机会非常大,这个值是一个巨大的错误。 half the classes 和编译器规则 (like strong typisation) 的作用就是防止 Progarmmer 犯下大错。所以他们强迫你使用 Add() 所以这样的错误不会发生。

【讨论】:

    【解决方案3】:

    实际上调用myArray[2] 并不会添加元素,而只是将对象分配到数组中的指定索引。如果数组的大小更小,你会得到一个IndexOutOfBoundsException,就像list&lt;T&gt; 一样。因此,在使用索引器的数组的情况下,假设您实际上拥有那么多元素:

    var array = new int[3];
    array[5] = 4; // bang
    

    这是因为数组的大小是固定的,您无法更改。如果您一个对象分配给一个大于数组大小的索引,您也会得到与 List&lt;T&gt; 相同的异常,这里没有区别。

    这里唯一真正的区别是,当使用new array[3] 时,您有一个大小为3 且索引最多为2 的数组,您可以调用array[2]。但是,这只会返回默认值 - 在int 的情况下,这是零。相反,当使用new List&lt;int&gt;(3) 时,您实际上并没有三个元素。事实上,该列表根本没有任何项目,调用list[2] 会引发异常。列表的参数只是 容量,它是运行时的一个参数,用于指示列表的底层数组何时应该调整大小 - 这是您的数组甚至没有的能力。

    【讨论】:

    • 我明白为什么我不能像在数组中那样存储元素。列表是否也将数据存储在连续的内存块中??如果它是一个数组,那么找到任何元素我需要固定时间,因为我知道第一个索引,并且因为它是一个连续的内存块,所以我可以计算任何位置的元素。你能解释一下遍历对列表的工作原理吗?
    • 查找列表中的元素是否需要恒定的时间?我仍然想知道这个。
    • 由于列表只是数组的包装,因此按索引访问元素会产生按索引访问底层数组。所以时间应该是差不多的。
    • 我确实从这个问题中得到了很多有用的信息,因为你和 Robin,我的疑问很清楚。谢谢。
    【解决方案4】:

    列表是一个数组包装器,其中内部数组大小由其方法管理。采用容量的构造函数只是在内部创建一个该大小的数组,但 count 属性(反映已添加的 count 元素)将为零。所以本质上,数组中的零个槽已经被赋值了。

    数组的大小由程序员管理。这就是为什么如果你想自己改变一个数组,你必须调用像System.Array.Resize这样的静态方法(注意数组参数是ref)。该方法为新的大小分配一块新的内存。

    总而言之,列表本质上为您管理一个数组,因此,权衡是您只能访问已添加到其中的尽可能多的类似数组的插槽。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-07
      • 1970-01-01
      • 2014-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多