web-dev-qa-db-ja.com

Big O表記とは何ですか?使っていますか?

Big O表記とは何ですか?使っていますか?

私は私が推測するこの大学のクラスを逃した:D

誰かがそれを使用し、彼らがそれを使用した場所のいくつかの実際の例を挙げていますか?


参照:

8歳のBig-O?
Big O、どのように計算/概算しますか?
実際に計算複雑性理論を適用しましたか?

28
Brian G

Big-Oについて話すときにほとんどの人が忘れている重要なことの1つは、次のことを言及する必要があると感じています。

Big-Oを使用して、2つのアルゴリズムの速度を比較することはできません。 Big-Oは、処理されるアイテムの数を2倍にした場合にアルゴリズムが(およそ)どれだけ遅くなるか、または数を半分に減らした場合にどれだけ速くなるかを示すだけです。

ただし、2つのまったく異なるアルゴリズムがあり、一方(A)がO(n^2)で、もう一方(B)がO(log n)である場合、 ABより遅いとは言われていません。実際、100個のアイテムがある場合、ABよりも10倍高速になる可能性があります。 200個のアイテムがある場合、Aは係数n^2だけ遅くなり、Bは係数log nだけ遅くなるとだけ書かれています。したがって、両方をベンチマークし、Aが100個のアイテムを処理するのにかかる時間と、同じ100個のアイテムにBが必要とする時間を知っていれば、Aの方が高速です。 Bよりも、BAを追い抜くアイテムの量を計算できます(Bの速度は、 A、遅かれ早かれAを追い越します—これは確かです)。

31
Mecki

Big O表記は、アルゴリズムの制限要因を示します。アルゴリズムの実行時間が入力に関連してどのようにスケーリングするかを簡略化して表現します。

例(Javaの場合):

_/** Takes an array of strings and concatenates them
  * This is a silly way of doing things but it gets the 
  * point across hopefully
  * @param strings the array of strings to concatenate
  * @returns a string that is a result of the concatenation of all the strings
  *          in the array
  */
public static String badConcat(String[] Strings){
    String totalString = "";
    for(String s : strings) {
        for(int i = 0; i < s.length(); i++){
            totalString += s.charAt(i);
        }
    }
    return totalString;
}
_

次に、これが実際に何をしているのかを考えてください。入力のすべての文字を調べて、それらを足し合わせます。これは簡単に思えます。問題は文字列は不変ですです。したがって、文字列に文字を追加するたびに、新しい文字列を作成する必要があります。これを行うには、古い文字列から新しい文字列に値をコピーして、新しい文字を追加する必要があります。

これは、最初の文字n回をコピーすることを意味します。ここでnは入力の文字数。文字を_n-1_回コピーするので、合計で_(n-1)(n/2)_コピーがあります。

これは_(n^2-n)/2_であり、Big O表記の場合、(通常は)最大のマグニチュード係数のみを使用し、それを掛けた定数をすべて削除すると、O(n^2)になります。

StringBuilderのようなものを使用すると、O(nLog(n))の線に沿ったものになります。最初に文字数を計算し、StringBuilderの容量を設定すると、O(n)になります。

したがって、1000文字の入力がある場合、最初の例では約100万回の操作が実行され、StringBuilderでは10,000回の操作が実行され、StringBuildersetCapacityでは1000回の操作が実行されます。同じこと。これは概算ですが、O(n)表記は桁違いであり、正確な実行時間ではありません。

それは私が定期的に言うことではありません。しかし、何かをするための最良のアルゴリズムを見つけようとするとき、それは常に私の心の奥底にあります。

8
Steve g

非常によく似た質問がすでに 8歳のBig-O? で尋ねられています。うまくいけば、そこの答えがあなたの質問に答えるでしょうが、そこの質問者はそれについて少し数学的な知識を持っていましたが、より完全な説明が必要な場合は明確にしないかもしれません。

4
Luke Bennett

「Big-O」表記は、nが非常に大きくなるにつれて、変数の2つの関数(たとえばn)の成長率を比較するために使用されます。関数fが関数gよりもはるかに速く成長する場合、g = O(f)は、nが十分に大きい場合、fは常に gよりも大きいことを意味します。倍率まで。

これは、コンピュータサイエンス、特にアルゴリズムの分析において非常に有用なアイデアであることがわかります。これは、たとえば2つの異なるアルゴリズムにかかる時間を表す関数の成長率に正確に関係していることが多いためです。非常に大雑把に言えば、t1 = O(t2)十分な大きさの場合、実行時t1(n)のアルゴリズムは実行時t2(n)のアルゴリズムよりも効率的であると判断できます。 nは通常、問題の「サイズ」です。たとえば、配列の長さやグラフ内のノードの数などです。

Nが十分に大きくなるというこの規定により、多くの有用なトリックを引き出すことができます。おそらく最も頻繁に使用されるのは、関数を最も急速に成長する用語まで単純化できることです。たとえば、n ^ 2 + n = O(n ^ 2)は、nが十分に大きくなると、n ^ 2項がnよりも非常に大きくになるため、n項は実質的に重要ではありません。だから私たちはそれを考慮から外すことができます。

ただし、これは、big-O表記が小さいnに対してあまり役に立たないことを意味します。これは、忘れてしまった成長の遅い用語が、実行時に影響を与えるほど重要であるためです。

私たちが今持っているのは、2つの異なるアルゴリズムのコストを比較するためのツールであり、一方が他方よりも速いまたは遅いと言うための省略形です。 Big-O表記は悪用される可能性がありますが、これはすでに十分に不正確であるため残念です。関数が別の関数よりも速く成長しないこと、および2つの関数が同じ速度で成長することを言うのと同等の用語があります。

ああ、私はそれを使用しますか?はい、常に-自分のコードがどれほど効率的であるかを理解しているとき、それはコストの優れた「封筒裏の計算」を提供します。

3
HenryR

すべてのプログラマーは、Big O表記とは何か、それが一般的なデータ構造とアルゴリズムを使用するアクションにどのように適用されるか(したがって、解決している問題に対して正しいDSとアルゴリズムを選択する)、および計算方法を知っている必要があります。それは彼ら自身のアルゴリズムのためです。

1)これは、データ構造で作業するときのアルゴリズムの効率の測定順序です。

2)「add」/「sort」/「remove」のようなアクションは、異なるデータ構造(およびアルゴリズム)で異なる時間がかかる可能性があります。たとえば、「add」と「find」はO(1)です。ハッシュマップの場合ですが、バイナリツリーの場合はO(log n)です。プレーン配列を扱う場合、ソートはQuickSortの場合はO(nlog n)ですが、BubbleSortの場合はO(n ^ 2)です。

3)計算は、アルゴリズムのループ深度を一般的に調べることで実行できます。ループなし、O(1)、すべてのセットを反復するループ(ある時点で発生した場合でも)O(n)。ループが各反復で検索スペースを半分にする場合はどうなりますか? O(log n)。ループのシーケンスの最高のO()を取り、ループをネストするときにO()を乗算します。

ええ、それよりも複雑です。あなたが本当に興味があるなら、教科書を手に入れてください。

3
JeeBee

Big-Oの背後にある「直感」

Xが無限大に近づくときのx上の2つの関数間の「競合」を想像してみてください:f(x) and g(x)。

ここで、(あるx)のある時点から、一方の関数の値が常に他方よりも高い場合は、この関数をもう一方の関数よりも「高速」と呼びましょう。

したがって、たとえば、x> 100ごとに、f(x)> g(x)であることがわかる場合、f(x)は "より高速です"g(x)より。

この場合、g(x) = O(f(x))。f(x)は一種の「速度制限」をもたらします。 g(x)をソートします。これは、最終的にはg(x)を通過し、永久に残してしまうためです。

これは、 big-O表記 の定義とは異なります。これは、f(x)は、C * g(x)よりも大きくする必要があるだけです。いくつかの定数C(これはあなたが助けることができないと言う別の言い方ですg(x)定数係数を掛けることによって競争に勝つ-f(x)は常に最終的に勝ちます)正式な定義も絶対値を使用しますが、私はそれを直感的にすることができたと思います。

3
Assaf Lavie

多くのアルゴリズムの複雑さは、特に多次元の問題では、複数の変数に基づいていることも考慮する価値があります。たとえば、私は最近、次のアルゴリズムを作成する必要がありました。 n個のポイントとm個のポリゴンのセットが与えられた場合、任意のポリゴンにあるすべてのポイントを抽出します。複雑さは、2つの既知の変数nとm、および各ポリゴンにあるポイントの数が不明であることに基づいています。ここでの大きなO表記は、O(f(n))またはO(f(n) + g(m))よりもかなり複雑です。 )。BigOは、多数の同種のアイテムを扱う場合に適していますが、常にそうであるとは限りません。

データに対する実際の反復回数は、多くの場合、データに依存することにも注意してください。クイックソートは通常高速ですが、事前にソートされたデータを与えると速度が低下します。私のポイントとポリゴンの対数は、データがどのように編成される可能性が高いか、およびnとmの相対的なサイズに関する事前の知識に基づいて、O(n +(m log(m))に近い非常に高速になりました。異なる相対サイズのランダムに編成されたデータではひどく。

最後に考慮すべきことは、アルゴリズムの速度とそれが使用するスペースの量の間には、しばしば直接的なトレードオフがあるということです。 鳩の巣ソート はこの良い例です。ポイントとポリゴンに戻って、すべてのポリゴンがシンプルですばやく描画でき、それぞれ一定の時間で画面に塗りつぶして、たとえば青で描画できたとしましょう。したがって、黒い画面にm個のポリゴンを描画すると、O(m)時間がかかります。n個のポイントのいずれかがポリゴン内にあるかどうかを確認するには、そのピクセルがその位置にあるかどうかを確認するだけです。ポイントは緑または黒です。したがって、チェックはO(n)であり、全体の分析はO(m + n)です。もちろん、実世界の座標をミリメートル単位で処理する場合、ほぼ無限のストレージが必要になるという欠点があります。 ......うーん。

2
SmacL

最悪の場合だけでなく、償却時間も考慮する価値があるかもしれません。これは、たとえば、アルゴリズムをn回実行すると、平均してO(1)になることを意味しますが、場合によってはさらに悪化する可能性があります。

良い例は動的テーブルです。これは基本的に、要素を追加すると拡張する配列です。単純な実装では、追加される要素ごとに配列のサイズが1ずつ増加します。つまり、新しい要素が追加されるたびにすべての要素をコピーする必要があります。これにより、O(n2この方法を使用して一連の配列を連結する場合のアルゴリズム。別の方法は、より多くのストレージが必要になるたびにアレイの容量を2倍にすることです。追加はO(n)操作である場合もありますが、追加するすべてのn要素に対してO(n)要素をコピーするだけで済みます。したがって、操作は平均してO(1)です。これは、StringBuilderまたはstd :: vectorのようなものが実装される方法です。

2
Jay Conrod

ウィキペディアから.....

Big O表記は、アルゴリズムの効率を分析するときに役立ちます。たとえば、サイズnの問題を完了するのにかかる時間(またはステップ数)は、T(n) = 4n²− 2n +2であることがわかります。

Nが大きくなると、n²項が支配的になるため、他のすべての項は無視できます。たとえば、n = 500の場合、項4n²は2n項の1000倍になります。後者を無視しても、ほとんどの目的で式の値に与える影響はごくわずかです。

明らかに私はそれを使ったことがありません。

1
Brian G

アルゴリズムの複雑さを評価できるはずです。これは、必要な要素の数に関する知識と組み合わせると、そのタスクに適していないかどうかを判断するのに役立ちます。

1
Bernard

最悪の場合、アルゴリズムの反復回数を示します。

リスト内のアイテムを検索するには、アイテムを取得するまでリストをトラバースできます。最悪の場合、アイテムは最後の場所にあります。

リストにn個のアイテムがあるとしましょう。最悪の場合、n回の反復を行います。 Big O表記では、O(n)です。

それは事実上、アルゴリズムがどれほど効率的であるかを示しています。

0
Ikke