次のネストされたループのBig-O時間の複雑さは何ですか。
for(int i = 0; i < N; i++)
{
for(int j = i + 1; j < N; j++)
{
System.out.println("i = " + i + " j = " + j);
}
}
O(N ^ 2)でしょうか?
ええ、それはまだO(n ^ 2)で、定数係数は小さくなっていますが、それはO表記には影響しません。
はい。 Big-Oの定義を思い出してください:O(f(n))定義により、ランタイムT(n)≤kf(n)一定の定数kの場合。この場合、ステップ数は(n-1)+(n-2)+ ... +となり、0からn-1の合計に再配置されます。これは
T(n(n-1)((n-1)+1)/ 2)==。
それを並べ替えると、T(n)が常に≤1/2(n²)になることがわかります。定義により、したがってT(n O(n²))==です。
System.out.printlnを無視すると、Nの2乗になります。その出力にかかる時間が線形であることを想定している場合(もちろん、そうでない場合もあります)、最終的にO((N ^ 2)* log N)になると思います。
私はこれをうるさいというわけではなく、複雑さを計算するときに明白なループを考慮する必要がないことを指摘するだけです。あなたが呼ぶものの複雑さも調べる必要があります。
はい、Nの2乗になります。実際のステップ数は、1からNの合計、つまり.5 *(N-1)^ 2です。 Big Oは最高の指数のみを考慮し、定数は考慮しないため、これは依然としてNの2乗です。
N = 10の場合、反復は10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1になります。 (これは、10回の反復+ 9回の反復+ 8回の反復などです)。
ここで、Nを何回得ることができるか(例では10)を加算に見つける必要があります。
1:(10)、2:(9 + 1)、3:(8 + 2)、4:(7 + 3)、5:(6 + 4)。これは5回です...そして5回の反復を行います。
これで、5の数+ 5があることがわかります。
10(5)+ 5
f(n)(またはN)の観点から、これは次のようになることが簡単にわかります。
f(n)= n(n/2) + n/2 =(n ^ 2)/ 2 + n/2 =(n ^ 2 + n)/ 2 ...これまさにこれらのネストされたループの複雑さです。
しかし、Big Oの漸近的な振る舞いを考えると、単一のnと分母であるf(n)のあまり重要でない値を取り除くことができます。
結果:O(n ^ 2)
指定されたプログラムの場合:
for (int i = 0; i < n; i++)
for (int j = i; j < n; j++)
println(...);
N = 3を考えます。
i
の値は0、1、2です。
For i = 0: println will execute 3 times
for i = 1: println will execute 2 times
for i = 2: println will execute 1 times
したがって、println
関数は3 + 2 + 1回、つまりn(n + 1)/ 2回実行されます。
したがって、O(n(n + 1)/ 2)= O(n ^ 2)です。