web-dev-qa-db-ja.com

ネストされたforループの時間の複雑さ

次のコードの時間の複雑さを計算する必要があります。

for (i = 1; i <= n; i++)
{
  for(j = 1; j <= i; j++)
  {
   // Some code
  }
}

O(n ^ 2)

28
yyy

はい、ネストされたループは、大きなO表記をすばやく取得する1つの方法です。

通常(常にではありませんが)、1つのループが別のループにネストされると、O(n²)が発生します。

考えてみてください。内側のループはi回iの値ごとに実行されます。外側のループはn回実行されます。

したがって、次のような実行パターンが表示されます:1 + 2 + 3 + 4 + ... + n回

したがって、明らかにn回以上実行する(下限)と言うことでコードの実行回数を制限できますが、nに関してはコードを何回実行しますか?

数学的には、n²回しか実行されず、最悪のシナリオが発生するため、O(n²)のBig-Oh境界は数学的に言えます。 (数学的にこれを見ることができる方法の詳細については Power Series

Big-Ohは、実行されている作業量を常に正確に測定するわけではありませんが、通常、最悪のシナリオの信頼できる近似を提供します。


4年後編集:この投稿はかなりの量のトラフィックを得るようだからです。べき級数を使用して実行をO(n²)にバインドする方法をより完全に説明したい

ウェブサイトから:1 + 2 + 3 + 4 ... + n =(n²+ n)/ 2 =n²/ 2 + n/2。それでは、これをO(n²)に変換する方法を教えてください。 (基本的に)言っているのは、n²> =n²/ 2 + n/2です。これは本当ですか?簡単な代数をしましょう。

  • 両側に2を掛けて取得:2n²> =n²+ n?
  • 2n²を展開して、n²+n²> =n²+ n?を取得します。
  • 両側からn²を引くと、n²> = n?が得られます。

Nが常に整数であると仮定すると、n²> = n(厳密には、n = 0または1の場合より大きくない)であることは明らかです。

実際のBig Oの複雑さは、私が今言ったものとは少し異なりますが、これがその要点です。実際には、Big Oの複雑度は、十分に大きい入力に対して、ある関数に他の関数よりも大きい定数を適用できるかどうかを尋ねます( wikipedia ページを参照)

48
AndyG

これを簡単に説明する方法は、視覚化することです。

iとjの両方が0からNの場合、O(N ^ 2)が見やすい

O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O
O O O O O O O O

この場合、次のとおりです。

O
O O
O O O
O O O O
O O O O O
O O O O O O
O O O O O O O
O O O O O O O O

これはN ^ 2の1/2であることがわかりますが、これはまだO(N ^ 2)です

30
Krys Jurgowski

実際、O(n ^ 2)です。同じランタイム here を使用した非常に類似した例も参照してください。

9
Chris Bunch

最初に、内側のループの反復回数が外側のループのインデックスの値に依存しないループを検討します。例えば:

 for (i = 0; i < N; i++) {
     for (j = 0; j < M; j++) {
         sequence of statements
      }
  }

外側のループはN回実行されます。外側のループが実行されるたびに、内側のループがM回実行されます。その結果、内側のループのステートメントは合計でN * M回実行されます。したがって、2つのループの合計複雑度はO(N2)です。

0
napender

外側のループ(i == 1)の最初の反復で、内側のループは外側のループ(i == 2)の2回目の反復で1回繰り返されます。 (i = 3)、内部ループは3回繰り返されます


外側のループの最終的な反復(i == n)で、内側のループはn回反復します

したがって、内部ループ内のステートメントの合計回数は、1からnまでの整数の合計に等しくなります。

((n)*n) / 2 = (n^2)/2 = O(n^2) times 
0
user2831683