2017-02-23 104 views
0

有很多关于对阵列forforeach循环和IEnumerable S IN表现一般职位。不幸的是,他们主要处理与foreach循环相关的开销,我无法在链接列表上找到任何关于其性能的任何明确信息 - 或者更确切地说,是List<T>性能for/while循环VS名单上foreach循环<T>


为了保持简单,我将提出我的问题作为两个假设,并询问它们是否正确。

假设1

当我运行下面的代码:

List<Foo> list = new List<Foo>(); 

//(list is filled here) 

foreach (Foo f in list) 
{ 
    f.baz(); 
} 

循环迭代要执行这样的:

0:你有一个指针到节点0通话节点0的项目上的baz()。将指针移至节点0之后的节点。

1:您有一个指向节点1的指针。在节点1的项目上调用baz()。将指针移动到节点1之后的节点。

2:您有指向节点2的指针。请在节点2的项目上调用baz()。指针移动到节点节点2

后...

N:你有一个指向节点n。在节点n的项目上调用baz()。在节点n之后将指针移动到节点。

换句话说,上面的代码具有O(n)的复杂性。

假设2

当我运行下面的代码:

List<Foo> list = new List<Foo>(); 

//(list is filled here) 

for (int i = 0; i < list.Count; i++) 
{ 
    list[i].baz(); 
} 

或以下代码:

List<Foo> list = new List<Foo>(); 

//(list is filled here) 

int i = 0; 
while (i < list.Count) 
{ 
    list[i].baz(); 
    i++; 
} 

循环迭代要执行这样的:

0:你有一个指向01的指针。从list获取指向节点0的指针。在节点0的项目上调用baz()

1:您有一个指向list的指针。从list获取指向节点0的指针。移动指针到节点0之后的节点。在节点1的项目上调用baz()

2:您有一个指向list的指针。从list获取指向节点0的指针。在节点0之后将指针移动到节点。将节点1之后的节点移动到节点。在节点2的项目上调用baz()

...

N:你有一个指针list。从list获取指向节点0的指针。将指针移至节点0之后的节点。将指针移至节点1之后的节点。将指针移至节点2之后的节点。[...]将指针移至节点(n-2)之后的节点。在节点(n-1)之后移动指针到节点。在节点n的项目上调用baz()

换句话说,上面的代码具有O(n )的复杂性。


我的假设是否正确?

+1

'List'不是一个链表,你可以从阅读这个类型的文档中看到。 – Servy

+1

您所做的主要假设不正确的是,链接列表和列表具有可比性。他们不是。其中一个显着差异是链接列表中的元素不能直接访问,而列表则可直接访问元素。这会导致假设2中的错误假设。将列表视为与数组相同的类别可能会有帮助。 – hatchet

+0

另外,由于枚举器可以维护状态(它们在哪里),即使LinkedList枚举器可以在由foreach使用时(foreach使用封面下的枚举器)提供O(n)。 – hatchet

回答

1

不,你的假设是不正确的。 List<T>数据类型由数组而不是链接列表支持。逻辑将是

0:你有一个参考列表。获取内部数组并直接跳转到第0个索引。在节点0的项目上调用 baz()。

1:你有一个refrence列出。获取内部数组并直接跳转到第一个索引的偏移量。在节点1的项目上调用 baz()。

2:你有一个参考列表。获取内部数组并直接跳转到第二个索引的偏移量。在节点2的项目上调用 baz()。

...

n:您有参考清单。获取内部数组并直接跳转到第n个索引的偏移量。在节点n的项目上调用 baz()。

如果用LinkedList<T>你描述的工作会在哪里正确但LinkedList<T>没有一个索引属性[i],所以你不能够在指数通过检索喜欢你的代码示例一样。

+1

_“的LinkedList 没有一个索引属性[I]” _ - 尽管,一个天真的程序员可以使用'Enumerable.ElementAt()'从一个链表,这当然将是可怕的准确检索由索引元素OP担心的方式。 –