web-dev-qa-db-ja.com

ネストされたループのBig-O

Big-O でこの投稿を読んでいます。
次のコードはO(n ^ 2)であると表示されています。

bool ContainsDuplicates(String[] strings)
{
    for(int i = 0; i < strings.Length; i++)
    {
        for(int j = 0; j < strings.Length; j++)
        {
            if(i == j) // Don't compare with self
            {
                continue;
            }

            if(strings[i] == strings[j])
            {
                return true;
            }
        }
    }
    return false;
}

しかし、なぜか分かりません。
内側のループは一定のことをします。
つまり、定数の1 .... Nの合計です。つまり、定数O(1)です。
外側のループはO(1)の総和です。
それで、n * O(1)だと想像します。

私はここで何かを誤解していると思います。
すべてのネストされたループがO(n ^ 2)を意味するとは思いませんか?

8
user10326

あなたの間違いは内側のループです。それは何か定数n回を実行するので、[〜#〜] o [〜#〜])。外側のループは内側のループをn回実行するため、[〜#〜] o [〜#〜] × )、または[〜#〜] o [〜#〜]2)。

一般に、ループの反復回数が入力のサイズに依存している場合、それは O)。そしてkそのようなループがネストされている場合、それは[〜#〜] o [〜#〜]k)。

18
KeithB

文字列の長さがnの場合、_i == j_のテストはn ^ 2回実行されます。アルゴリズムの順序は、アルゴリズムのどの部分でも最高の順序です。 'i'は 'j'とn ^ 2回比較されるため、アルゴリズムの順序はO(n^2)よりも小さくなることはありません。

非常に大きな「n」の場合、「n」を2倍にすると、実行時間が4倍になります。

4
David Schwartz

定数演算の意味を誤解しています。

定数操作は、受け取る入力に関係なく、常に一定の時間内に実行される操作です。

i == jは、このステートメントを一定の時間で実行するため、定数演算です。それは1単位時間かかるとしましょう。

しかし、この定数演算は(iの値がない)*(jの値がない)回実行されます。 iとjがそれぞれ10回実行されるとしましょう。次に、ネストされたループで計算すると、i == jの完了に100単位の時間がかかります。したがって、iとjの値が変化すると、それは変化します。

I == jは1単位時間で実行されますが、i == jが実行される回数はわかりません。

N回実行すると、n単位の時間がかかります。外部ループは内部ループをn回実行します。つまり、本質的にi == jの演算はn ^ 2回行われます。

すべてのネストされたループはO(n ^(ネストされたループの数))を意味します。ここでOは、コードがO()の値以下で実行されることを意味する上限を意味します。これは、それより長くはかからないという保証ですが、それほど長くはかからなくてもかまいません。

2
codecool

ネストされたループはO(1 * 私2 * ... * 私)、ここでnはネストされたループの数であり、 バツ ループの反復回数ですx。 (または、別の言い方をすれば、それは各ループの反復回数の積です。)

ループのペアは、同じ配列を2回繰り返します。これは、偶然にO(n * n)またはO(nです。2)。

最も内側のループ内で発生することは常に発生するため、定数として扱われます。 Big-O表記は、実際には線形コードのパフォーマンスを測定することではなく、次の項目が与えられたときに反復アルゴリズムがどのように動作するかを相対的に比較することに関するものですnアイテム対処する入力。実際に反復を行わない特定の操作(スタックでのプッシュまたはポップなど)は、データの1つの要素を処理するため、O(1))と表示されます。

0
Blrfl