Reputation: 622
There are plenty of posts about performance of for
and foreach
loops on arrays and IEnumerable
s in general. Unfortunately, they deal mostly with overheads related to foreach
loop, and I can't find anything clear about their performance on linked lists - or rather List<T>
.
To keep things simple, I'm going to present my question as two assumptions, and ask if they are correct.
When I run the following code:
List<Foo> list = new List<Foo>();
//(list is filled here)
foreach (Foo f in list)
{
f.baz();
}
loop iterations are going to execute like this:
0: You have a pointer to node 0. Call
baz()
on node 0's item. Move pointer to the node after node 0.1: You have a pointer to node 1. Call
baz()
on node 1's item. Move pointer to the node after node 1.2: You have a pointer to node 2. Call
baz()
on node 2's item. Move pointer to the node after node 2....
n: You have a pointer to node n. Call
baz()
on node n's item. Move pointer to the node after node n.
In other words, the code above has O(n) complexity.
When I run the following code:
List<Foo> list = new List<Foo>();
//(list is filled here)
for (int i = 0; i < list.Count; i++)
{
list[i].baz();
}
or the following code:
List<Foo> list = new List<Foo>();
//(list is filled here)
int i = 0;
while (i < list.Count)
{
list[i].baz();
i++;
}
loop iterations are going to execute like this:
0: You have a pointer to
list
. Get pointer to node 0 fromlist
. Callbaz()
on node 0's item.1: You have a pointer to
list
. Get pointer to node 0 fromlist
. Move pointer to the node after node 0. Callbaz()
on node 1's item.2: You have a pointer to
list
. Get pointer to node 0 fromlist
. Move pointer to the node after node 0. Move pointer to the node after node 1. Callbaz()
on node 2's item....
n: You have a pointer to
list
. Get pointer to node 0 fromlist
. Move pointer to the node after node 0. Move pointer to the node after node 1. Move pointer to the node after node 2. [...] Move pointer to the node after node (n-2). Move pointer to the node after node (n-1). Callbaz()
on node n's item.
In other words, the code above has O(n2) complexity.
Are my assumptions correct?
Upvotes: 0
Views: 1241
Reputation: 127543
No, your assumptions are incorrect. The List<T>
data type is backed by an array not a Linked List. The logic would be
0: You have a refrence to list. Get the internal array and directly jump to the 0th index. Call baz() on node 0's item.
1: You have a refrence to list. Get the internal array and directly jump to the 1st index's offset. Call baz() on node 1's item.
2: You have a refrence to list. Get the internal array and directly jump to the 2nd index's offset. Call baz() on node 2's item.
...
n: You have a refrence to list. Get the internal array and directly jump to the nth index's offset. Call baz() on node n's item.
If you where working with a LinkedList<T>
your description would be correct however LinkedList<T>
does not have a indexer property [i]
so you would not be able to pass in a index to retrieve like your code example does.
Upvotes: 1