2016-01-21 11 views
12

アルゴリズムの複雑さがn^cで、ループのネストされたものの数だけを描くことができます。Big Oの例2^n

for (var i = 0; i < dataset.len; i++ { 
    for (var j = 0; j < dataset.len; j++) { 
     //do stuff with i and j 
    } 
} 

ログインが半分のたびに設定されているデータを分割何かで、バイナリ検索は、この(ように見えるこのためどのようなコード全くわからないが)ありません。

しかし、c^n、より具体的には2^nのアルゴリズムの簡単な例は何ですか。 O(2^n)はデータによるループに基づいていますか?またはデータの分割方法は?それとも全く別のもの?

答えて

14

実行時間O(2^N)のアルゴリズムは、サイズN-1の2つのより小さい問題を再帰的に解くことによってサイズNの問題を解決する再帰アルゴリズムです。

このプログラムは、例えば、擬似コードにおけるN個のディスクの有名な「タワーハノイの」課題を解決するために必要なすべての移動

void solve_hanoi(int N, string from_peg, string to_peg, string spare_peg) 
{ 
    if (N<1) { 
     return; 
    } 
    if (N>1) { 
     solve_hanoi(N-1, from_peg, spare_peg, to_peg); 
    } 
    print "move from " + from_peg + " to " + to_peg; 
    if (N>1) { 
     solve_hanoi(N-1, spare_peg, to_peg, from_peg); 
    } 
} 

レッツT(N)が要する時間であることを出力しN個のディスク。

我々は持っている:

T(1) = O(1) 
and 
T(N) = O(1) + 2*T(N-1) when N>1 

をあなたが繰り返し最後の項を展開すると、あなたが得る:

T(N) = 3*O(1) + 4*T(N-2) 
T(N) = 7*O(1) + 8*T(N-3) 
... 
T(N) = (2^(N-1)-1)*O(1) + (2^(N-1))*T(1) 
T(N) = (2^N - 1)*O(1) 
T(N) = O(2^N) 

を実際にこれを理解するには、あなただけの漸化式でその特定のパターンを知っている必要があります指数関数的な結果につながります。一般にT(N) = ... + C*T(N-1)C > 1はO(x^N)を意味します。参照:

https://en.wikipedia.org/wiki/Recurrence_relation

+0

N番目のフィボナッチ数を計算する素朴な再帰関数は、これのもう一つの古典的な例です。 –

+0

私はまだそのコードを見て2^nを導くことはできませんが、これは非常に役立ちます。 – dlkulp

+1

私は助けてくれる説明を追加しました –

8

可能な集合のすべての部分集合を反復する。この種のアルゴリズムは、例えば一般化されたナップザック問題のために使用される。

サブセットの繰り返しがどのようにO(2^n)に変換されるのか分かりにくい場合は、n個のスイッチのセットを想像してください。それぞれのスイッ​​チはセットの1つの要素に対応します。ここで、各スイッチをオンまたはオフにすることができます。サブセットにあると「オン」と考えてください。可能な組み合わせ数は2^nです。

コード内の例を見たい場合は、ここでは再帰について考えるのが簡単ですが、他のすばらしい例は考えられません。

+0

一般的なケースは、再帰的のようなものを実装しています。 –

+0

@SanketMakaniビット長 'n'のすべての2進数を反復処理すると' O(n * 2^n) 'にどのように相関しますか?当然のことながら、nビットの数字を 'O(n)'に増やすことを前提としていない限り(IMHOは完全に正しいですが、*多くは同意しません*) これは、 'n'数字を反復すると、 'O(n log n)'は、1ビット演算をカウントすると正しいが、通常はいくつかの仮定が行われる。 – Marandil

+0

すべての可能な '2^n'の数を反復するとき、要素が存在するかどうかをチェックするために、その数の各ビットをチェックする必要があります。ビットがセットされているかどうかを確認するには 'O(1)'の時間がかかることを考慮すると、 'n^2 '個のそれぞれに対して' n'回繰り返すように 'n'ビットを繰り返し処理する必要があります。したがって、全体の複雑さは 'O(n * 2^n)'になります。 –

1
int Fibonacci(int number) 
{ 
    if (number <= 1) return number; 

    return Fibonacci(number - 2) + Fibonacci(number - 1); 
} 

入力データセットごとに増加すると倍増します。 O(2N)関数の成長曲線は指数関数的であり、非常に浅く始まり、次に気象的に上昇する。 ビッグO(2^n)との私の例が、はるかに優れてはこれです:

public void solve(int n, String start, String auxiliary, String end) { 
    if (n == 1) { 
     System.out.println(start + " -> " + end); 
    } else { 
     solve(n - 1, start, end, auxiliary); 
     System.out.println(start + " -> " + end); 
     solve(n - 1, auxiliary, start, end); 
    } 

この方法のプログラムでは、「ハノイの塔」問題を解決するために、すべての動きを出力します。 どちらの例も問題を解決するために再帰的に使用しており、大きなO(2^n)の実行時間を持っていました。

+0

なぜ指数関数的な複雑さがあるのか​​を説明する必要があります。また、悪い例です。このアルゴリズムを簡単に「修正」して線形の複雑さを持たせることができます。つまり、目的に応じて処理能力を無駄にしたいのと同じです。より良い例は、ハード/不可能な高速を計算するアルゴリズムを示します。 – anatolyg

0

C^N = cサイズのアルファベットからn要素のすべての組み合わせ。

より具体的には、2^NはすべてNビットで表現可能な数字です。これは実際には `O(N * 2^n)の`複雑である

vector<int> bits; 
int N 
void find_solution(int pos) { 
    if (pos == N) { 
    check_solution(); 
    return; 
    } 
    bits[pos] = 0; 
    find_solution(pos + 1); 
    bits[pos] = 1; 
    find_solution(pos + 1); 
}