web-dev-qa-db-ja.com

アルゴリズムの実行時間の推定

たとえば、私がO(n2)そして、問題サイズが1000の場合、それは10秒間実行されます。問題サイズを2000に2倍にした場合、おおよその実行時間を秒単位で知りたいと思います。私はその答えを知っていますが、答えに到達する方法の論理を理解したいと思います。これが私が考えていることです。

N = 1000 , Therefore 1000^2 = 10 seconds
N = 2000,  Therefore (2*1000)^2, // stuck here

2の2のべき乗が4であり、10秒に4を掛けて40秒になるので、40秒になることはわかっていますが、これが正しいかどうかは完全にはわかりません。誰かが簡単な言葉でそれを分解できるかどうか疑問に思っていましたか?

3
user2733436

O(n)O(n²)などの複雑なクラスは、実際の実行時間を計算するためのものではありません。代わりに、入力サイズを変更したときのさまざまなアルゴリズムのスケーリングを比較するためのものです。

たとえば、ここでは、一致する各アイテムにfrobnicate(a, b)を適用する2つのアルゴリズムがあります。

_void algorithm1(Set<int> items) {
  for (int i in items) {
    for (int j in items) {
      if (i == j) {
        frobnicate(i, j);
      }
    }
  }
}

void algorithm2(Set<int> items) {
  for (int i in items) {
    frobnicate(i, i);
  }
}
_

明らかに、1番目のアルゴリズムはO(n²)の複雑さで、2番目のアルゴリズムはO(n)です。したがって、_algorithm2_は大規模な入力に適していると結論付けることができます。しかし、これは別のO(n)アルゴリズムです:

_void algorithm3(Set<int> items) {
  sleep(9 seconds);
  for (int i in items) {
    sleep(1 millisecond);
    frobnicate(i, i);
  }
}
_

これは_algorithm2_と同様にスケーリングしますが、常に遅くなります!実際、O(n²) _algorithm1_は、小さな入力に対してこのアルゴリズムよりも優れています! _algorithm3_のオーバーヘッドは9秒に固定されているため、O(n)複雑度の式に異なる数値を代入して、異なる入力サイズにかかる時間を調べることはできません。

例:

_n=1000 => algorithm3 takes 10 seconds
n=2000 => algorithm3 takes 11 seconds, not 20 seconds!
_

実際には、実行時間を確実に計算することはできません。各アトミック操作のコストを把握できたとしても、キャッシュ境界などのハードウェアの癖が邪魔になります。信頼できる唯一のオプションは、さまざまな入力サイズで統計的サンプリングを行い、次に、予想される複雑さのクラスに一致する推定関数を収集されたデータに適合させることです。

f(n) = a·n² + b·n + cの実行時推定関数(!=複雑度クラス)があると仮定し、単純化のために_b = c = 0_と仮定します(つまり、線形係数なし、一定のオーバーヘッドなし)。次に、データポイントf(1000) = 10 secondsからパラメータaを計算できます。

_10 seconds = f(1000)
           = a·1000²
           = a·1000000
 <=> a = 10/1000000 seconds = 1/100000 seconds
_

したがって、f(n) = n²/100000 seconds。 _n = 2000_をプラグインすると、

_f(2000) = 2000²/100000 seconds
        = 4000000/100000 seconds
        = 40 seconds
_

これは、入力サイズにn(ここでは_n = 2_)を掛けると、出力は__(ここでは_n² = 4_)だけ増えるというショートカットと一致しています。

11
amon

短くするには:

アモンの答えの最初の文は重要です。

しかし、あなたの推測も正しいです:1000^2(2*1000)^2の4倍です。つまり特定のハードウェアで1000^2が10秒に等しい場合、(2*1000)^2は40秒に等しくなります。それは単に3つの法則です。

もう1つ注意:アルゴリズムのimplementationの実行時間を扱う場合は、実装のパフォーマンスもtestする必要があります。単純なプログラミングの「間違い」は、現実の世界で大きな違いを生む可能性があります。

0
fex