2016-10-03 4 views
-1

配列 'a'に1からNまでのランダム値(繰り返し値なし)を入力したいと思います。 randInt(i、j)のBig-OがO(1)であり、この関数がiからjまでランダムな値を生成すると仮定します。
出力の例を次に示します。乱数ジェネレータを使用するコードのBig-Oとは何ですか?

{1,2,3,4,5}または{2,3,1,4,5}または{5,4,2,1,3} 1,2,1,3,4}

#include<set> 
using std::set; 

set<int> S;// space O(N) ? 
int a[N]; // space O(N) 
int i = 0; // space O(1) 
do { 
    int val = randInt(1,N); //space O(1), time O(1) variable val is created many times ? 
    if (S.find(val) != S.end()) { //time O(log N)? 
     a[i] = val; // time O(1) 
     i++; // time O(1) 
     S.insert(val); // time O(log N) <-- we execute N times O(N log N) 
    } 
} while(S.size() < N); // time O(1) 

ザ・我々は1からN. にすべての値を生成するまでループを継続しますが私の理解では、設定が対数時間のログ(N)の値をソートすることで、 log(N)に挿入します。

Big-O = O(1) + O(X*log N) + O(N*log N) = O(X*log N) 

ここで、Xが多いほど、セット内にない数値を生成する可能性が高くなります。

time O(X log N) 

space O(2N+1) => O(N), we reuse the space of val 

?? randIntが実行されるたびにすべての異なる数値を生成するのは非常に難しいので、少なくともN回実行することを期待しています。
変数Xが何度も作成されていますか?
Xにはどのような価値がありますか?

+0

コードを書くことは、無限ループを持たないコードを書くことほど重要ではありません。 – kfsone

+0

あなたのランダムソースについては何も知らないのです。真にランダムであれば、最悪の場合のXは∞です。 – kfsone

答えて

3

RNGが理想的であるとします。つまり、randInt(1、N)を繰り返し呼び出すとi.i.dが生成されます。 {1、...、N}上に均一に分布した(独立して同一に分布した)一連の値。

(もちろん、現実にはRNGが理想的であること。しかし、それは数学容易になり以来のはそれで進むことはできません。)最初の反復で

平均場合

、ランダムな値val が選択されていますが、もちろんセットSには含まれていません。

次の反復では、別のランダム値が選択されます。確率(N-1)/ Nで

  • 、それはヴァルとは異なるであろうと内側条件が実行されます。この場合、選択した値の額をとしてください。
  • そうでなければ(確率1/Nで)、選択された値は、と等しくなります。リトライ。それはヴァル(ヴァルは異なる)有効になるまでの平均を取るんどのように多くの反復

が選択されていますか?確かに、私たちは確率(N-1)/ Nで成功する試行の独立したシーケンスを持っており、最初の成功まで平均で何回試行するかを知りたいと思っています。これは幾何学的分布であり、一般に、成功確率pを有する幾何分布は平均1/pを有する。したがって、平均してN /(N-1)回の試行が必要となる。。

同様に、N /(N-2)のようにヴァルとval からヴァルが別個選択する平均して試み、そしてかかります。最後に、N番目の値はN/1 = N回の平均値をとる。合計で

ループは、平均して

1 + N/(N-1) + N/(N-2) + ... + N/1 = N sum_{i=1}^N 1/i

回実行されません。和sum_{i=1}^N 1/iはN番目のharmonic numberであり、ln(N)でおおよそ近似することができます。 (もう少し複雑であり、Euler-Mascheroni constantを含むが、LN(N)は漸近的複雑さを見つけるために十分である、よく知られたbetter approximationがあります。)

だから近似に、反復の平均数はNになりますLN N.

アルゴリズムの残りの部分はどうですか? N個のものをセットに挿入するようなものは、ほとんどのO(N log N)時間かかるので、無視することができます。大きな残り事はS.の現在のサイズに対数時間を要しますが、選ばれた乱数値がSであるかどうかを確認する必要があり、各反復は、だから我々はその数値から

N sum_{i=1}^N ln(i)/i

を計算しなければならないということです実験は、大規模なN. の場合、N/2 *(ln N)^ 2にほぼ等しいと思われます。編集:短い非公式の証明はthis math.SE answerを参照してください。より正式な証明のためのother answer to that question

結論として、合計平均複雑度はΘ(N(ln N)^ 2)です。 この場合も、これはRNGが理想的であると仮定しています。

言及xaxxonと同様に最悪の場合

に、それは、アルゴリズムがまったく終了しないこと(そうが)原理的には可能です。したがって、最悪の場合の複雑さはO(∞)になります。

0

これは、目標を達成するための非常に悪いアルゴリズムです。

数字の1からNで配列を入力し、シャッフルしてください。

O(N)

https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

次に1とN-1とを入れ替える間の屈折率を選択、シャッフル0とN-1との間の屈折率を選択し、インデックス0でそれを交換するですインデックス1でリストの終わりまで。

具体的な質問に関しては、乱数ジェネレータの動作によって異なります。それが本当にランダムであれば、それは決して完了しないかもしれません。擬似乱数の場合は、ジェネレータの周期に依存します。期間が5の場合は、二重引用符を使用することはありません。

+0

私はこれが悪いアルゴリズムだと知っていますが、Big-Oの解析方法はわかりません。 – user2143819

+0

質問に答えません。 -1 – Mehrdad

+0

@mehrdad updated答え。 – xaxxon

-2

複雑な動作をする大惨事なコードです。最初の数を生成するのはO(1)です。次に、2番目にはバイナリ検索が行われるため、ログNとジェネレータの再実行に番号が見つかるはずです。新しい番号を得るチャンスはp = 1- i/Nです。したがって、再実行の平均回数は逆数であり、Nの別の因子を与えます。したがって、O(N^2 log N)です。

これを行う方法は、数値を生成してからシャッフルすることです。それはO(N)です。

+0

あなたは考慮に入れずにアルゴリズムを分析することはできません乱数ジェネレータの範囲前回の回答を削除して、それを新しい回答として貼り付けてしまったのですか? – xaxxon

+0

いいえ、私は検索がバイナリであることを忘れてしまったためです。しかし、乱数ジェネレータはO(1)であり、範囲は既知であるため、コードは振る舞いを定義し、分析することができます。 –

+0

これは、基礎となるアルゴリズムの範囲と周期性に依存します。おそらく実際には1-Nの数は生成されません。 – xaxxon

関連する問題