for
とforeach
ループのパフォーマンスについては多くの投稿とIEnumerable
が一般的です。残念ながら、ほとんどの場合、foreach
ループに関連するオーバーヘッドが処理されており、リンクされたリストのパフォーマンスについては何もわかりません(List<T>
)。for/whileループとforeachループのパフォーマンスリストの表示<T>
簡単にするために、私は2つの前提として質問を提示し、正しいかどうか質問します。
私は次のコードを実行すると仮定1
:
List<Foo> list = new List<Foo>();
//(list is filled here)
foreach (Foo f in list)
{
f.baz();
}
ループの反復は次のように実行しようとしている。
0:あなたは0コールをノードへのポインタを持っていますノード0のアイテムの
baz()
。ノード01後ノードへのポインタを移動します:あなたは、ノード1の項目には1.通話
baz()
をノードへのポインタを持っています。ノード12後ノードへのポインタを移動します:あなたは、ノード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へのポインタがあります。ノード0へのポインタを
list
から取得します。ノード0の項目でbaz()
と呼び出してください。1:あなたが
list
へのポインタを持っています。ノード0へのポインタをlist
から取得します。ノード0の後にノードへのポインタを移動します。ノード1のアイテムのbaz()
を呼び出します。2:あなたは
...list
へのポインタを持っています。ノード0へのポインタをlist
から取得します。ノード0の後のノードへのポインタの移動ノード1の後のノードへのポインタの移動ノード2のアイテムのbaz()
を呼び出します。N:あなたは
list
へのポインタを持っています。ノード0へのポインタをlist
から取得します。ノード0の後にノードへポインタを移動する。ノード1の後にノードへポインタを移動する。ノード2の後にノードへポインタを移動する。[...]ノード(n-2)の後のノードへのポインタを移動する。ノード(n-1)の後にノードへポインタを移動する。ノードnの項目のbaz()
に電話してください。
つまり、上記のコードでは、O(n )の複雑さがあります。
私の前提は正しいですか?
'List'はリンクされたリストではありません。そのタイプのドキュメントを読むことができます。 – Servy
あなたが間違っていると主張しているのは、リンクリストとリストが匹敵するということです。ではない。重要な違いの1つは、リンクリスト内の要素には直接アクセスできないが、List では要素に直接アクセスできる点である。これは、仮定2であなたの間違った前提につながります。リストを配列と同じカテゴリのように考えると役立ちます。 –
hatchet
また、列挙子は状態を維持できるので、LinkedList列挙子でもforeach(foreachはカバーの下の列挙子を使用します)で使用するとO(n)を出力できます。 – hatchet