关于数组和for
的{{1}}和foreach
循环的性能有很多帖子。不幸的是,他们主要处理与IEnumerable
循环相关的开销,而我无法找到关于他们在链接列表上的表现的任何明确内容 - 或者更确切地说是foreach
。
为了简单起见,我将把我的问题作为两个假设提出来,并询问它们是否正确。
当我运行以下代码时:
List<T>
循环迭代将按如下方式执行:
0:你有一个指向节点0的指针。在节点0的项目上调用
List<Foo> list = new List<Foo>(); //(list is filled here) foreach (Foo f in list) { f.baz(); }
。在节点0之后将指针移动到节点。1:您有一个指向节点1的指针。在节点1的项目上调用
baz()
。在节点1之后将指针移动到节点。2:你有一个指向节点2的指针。在节点2的项目上调用
baz()
。在节点2之后将指针移动到节点。...
n:你有一个指向节点n的指针。在节点n的项目上调用
baz()
。在节点n之后将指针移动到节点。
换句话说,上面的代码具有O(n)复杂度。
当我运行以下代码时:
baz()
或以下代码:
List<Foo> list = new List<Foo>();
//(list is filled here)
for (int i = 0; i < list.Count; i++)
{
list[i].baz();
}
循环迭代将按如下方式执行:
0:你有一个指向
List<Foo> list = new List<Foo>(); //(list is filled here) int i = 0; while (i < list.Count) { list[i].baz(); i++; }
的指针。从list
获取指向节点0的指针。在节点0的项目上调用list
。1:你有一个指向
baz()
的指针。从list
获取指向节点0的指针。在节点0之后将指针移动到节点。在节点1的项目上调用list
。2:你有一个指向
baz()
的指针。从list
获取指向节点0的指针。在节点0之后将指针移动到节点。在节点1之后将指针移动到节点。在节点2的项目上调用list
。...
n:你有一个指向
baz()
的指针。从list
获取指向节点0的指针。在节点0之后将指针移动到节点。在节点1之后将指针移动到节点。将节点移动到节点2之后的节点。 [...] 将节点移动到节点后的节点(n-2 )。将指针移动到节点(n-1)之后的节点。在节点n的项目上调用list
。
换句话说,上面的代码具有O(n 2 )复杂度。
我的假设是否正确?
答案 0 :(得分:1)
不,你的假设是不正确的。 List<T>
数据类型由数组支持,而不是链接列表。逻辑是
0:你有一个参考列表。获取内部数组并直接跳转到第0个索引。呼叫 baz()在节点0的项目上。
1:你有参考列表。获取内部数组并直接跳转到第一个索引的偏移量。呼叫 baz()在节点1的项目上。
2:你有一个参考列表。获取内部数组并直接跳转到第二个索引的偏移量。呼叫 baz()在节点2的项目上。
...
n:你有一个参考列表。获取内部数组并直接跳转到第n个索引的偏移量。呼叫 baz()在节点n的项目上。
如果使用LinkedList<T>
您的描述是正确的,但LinkedList<T>
没有索引器属性[i]
,那么您将无法传入索引来检索你的代码示例。