非反復乱数列生成アルゴリズム

非反復乱数列生成アルゴリズム

この記事では、ハッシュテーブルを使用して重複を排除する通常の方法よりもはるかに高速な、繰り返しのない乱数シーケンスを生成する効率的なアルゴリズムについて説明します。

まず、提案を見てみましょう。

正の整数 n が与えられた場合、長さ n の配列を出力する必要があります。配列の要素は 0 ~ n-1 の範囲の乱数であり、要素を繰り返すことはできません。たとえば、n = 3 の場合、要素の範囲が 0 から 2 までの長さ 3 の配列を取得する必要があります。

たとえば、0、2、1。

この問題の通常の解決方法は、ハッシュテーブルを設計し、ループしてランダムな数字を取得し、ハッシュテーブル内でその数字を探すことです。ハッシュテーブルに数字が存在しない場合は、それを出力します。このアルゴリズムのコードは以下の通りである。

  1. 公共 静的  int [] GetRandomSequence0( int合計)
  2. {
  3.      int [] ハッシュテーブル =新規  int [合計];
  4.      int [] 出力 =新規  int [合計];
  5.  
  6. ランダム random = new Random();
  7.      ( int i = 0 ; i < 合計; i++)の場合
  8. {
  9.          int num = random.Next( 0 , 合計);
  10.          while (ハッシュテーブル[num] > 0 )
  11. {
  12. num = ランダム.Next( 0 , 合計);
  13. }
  14.  
  15. 出力[i] = 数値;
  16. ハッシュテーブル[num] = 1 ;
  17. }
  18.  
  19.     出力を返します
  20. }

コードは非常にシンプルです。0 から total - 1 までループしてランダムな数字を取得し、ハッシュテーブル内でそれらの数字を一致させようとします。ハッシュテーブルに数字が存在しない場合は、それを出力し、ハッシュテーブルでその数字を 1 に設定します。それ以外の場合は、ハッシュテーブルにない数字が見つかるまでループしてランダムな数字を取得しようとします。このアルゴリズムの問​​題点は、乱数を取得するために試行し続ける必要があることです。ハッシュテーブルがいっぱいに近づくと、この試行が失敗する確率がどんどん高くなります。

繰り返し試行する必要のないアルゴリズムはありますか?答えはイエスです。

上の図に示すように、n = 4と仮定して順次配列を設計します。

最初のラウンドでは、0から3までの乱数を2として取ります。このとき、配列の2番目の数字を取り出して出力し、この数字を配列から削除します。このとき、配列は次のようになります。

2 回目のラウンドでは、0 から 2 までの乱数を 1 と仮定して、その位置の数字を出力し、配列からこの数字を削除します。これを配列の長さが 0 になるまで繰り返します。すると、ランダムな非繰り返しシーケンスが得られます。

このアルゴリズムの利点は、取得した数値を保存するためのハッシュテーブルを必要とせず、繰り返し試行する必要がないことです。アルゴリズムコードは次のとおりです。

  1. 公共 静的  int [] GetRandomSequence1( int合計)
  2. {
  3. リスト< int >入力 =新しいリスト< int >();
  4.      ( int i = 0 ; i < 合計; i++)の場合
  5. {
  6. 入力.Add(i);
  7. }
  8.  
  9. リスト< int >出力 =新しいリスト< int >();
  10.  
  11. ランダム random = new Random();
  12.      int終了 = 合計;
  13.      ( int i = 0 ; i < 合計; i++)の場合
  14. {
  15.          int num = random.Next( 0 , end);
  16. output.Add(入力[num]);
  17. 入力.RemoveAt(数値);
  18. 終わり - ;
  19. }
  20.  
  21.      output.ToArray()を返します
  22. }

このアルゴリズムは 2 つのループを 1 つのループに変更し、アルゴリズムの複雑さを大幅に軽減します。理論上は、速度は最初のアルゴリズムよりも速くなるはずです。しかし、現実はしばしば私たちの想像を超えています。total = 100000 の場合、テスト後、最初のアルゴリズムは 44 ミリ秒かかり、2 番目のアルゴリズムは 1038 ミリ秒かかり、これははるかに遅いです。これはなぜでしょうか?問題の鍵は input.RemoveAt にあります。配列要素を削除する場合、この配列要素の後のすべての要素を 1 つ前に移動する必要があることはわかっています。この移動操作には非常に時間がかかるため、アルゴリズムが遅くなります。この時点で、配列ではなくリンクリストを使用すれば削除が非常に高速になるのでは、と言う人がいるかもしれません。はい、リンクリストは要素の削除の効率性の問題を解決できますが、検索速度が大幅に低下し、配列のように配列要素の添え字に従って要素を直接見つけることはできません。したがって、リンク リストを使用しても機能しません。ここで行き詰まってしまったようです。ハッシュテーブルを使用して繰り返し試すことは可能でしょうか?以下の内容を読む前に、5分間考えてください。

#p#

...5分考えてみましょう

[[20734]]

#p#

アルゴリズムは窓紙の層のようなものです。窓紙を通しては、中に何が入っているかはわかりませんが、一度突き抜けてしまえば、とても単純なもののように見えます。

n = 4 と仮定して、上記と同じ例を使用しましょう。

最初のラウンドでランダムに 2 を取得した場合、配列から 2 を削除するのではなく、配列の最後の要素を 2 の位置に移動します。

配列は

2 回目のラウンドでは、0 から 2 までの乱数を選択します。この時点で、配列内の最後の使用可能な要素の位置は 3 ではなく 2 になっています。このとき得られた乱数が1であると仮定する。

次に、インデックス2の要素をインデックス1に移動し、配列は次のようになります。

n 個の要素が取り出されるまでこれを繰り返します。

このアルゴリズムの利点は、取得した数値を保存するためのハッシュテーブルが不要で、繰り返し試行する必要がなく、前のアルゴリズムのように配列要素を削除する必要がないことです。配列の有効な位置にある最後の要素を毎回現在の位置に移動するだけで済みます。これにより、アルゴリズムの複雑さが O(n) に軽減され、速度が大幅に向上します。

テストの結果、n=100000 の場合、このアルゴリズムには 7 ミリ秒しかかかりません。

以下はこのアルゴリズムの実装コードである。

  1. /// <要約>  
  2. /// イーグルトによるデザイン 
  3. /// </要約>  
  4. /// <param name="合計"></param>  
  5. /// <戻り値></戻り値>  
  6. 公共 静的  int [] GetRandomSequence2( int合計)
  7. {
  8.  
  9.      int [] シーケンス =新規  int [合計];
  10.      int [] 出力 =新規  int [合計];
  11.  
  12.      ( int i = 0 ; i < 合計; i++)の場合
  13. {
  14. シーケンス[i] = i;
  15. }
  16.  
  17. ランダム random = new Random();
  18.  
  19.      int終了 = 合計 - 1 ;
  20.  
  21.      ( int i = 0 ; i < 合計; i++)の場合
  22. {
  23.          int num = random.Next( 0 , end + 1 );
  24. 出力[i] = シーケンス[num];
  25. シーケンス[num] = シーケンス[end];
  26. 終わり - ;
  27. }
  28.  
  29.     出力を返します
  30. }

オリジナルリンク: http://www.cnblogs.com/eaglet/archive/2011/01/17/1937083.html

【編集者のおすすめ】

  1. 自分用の簡単な家計簿を作成する
  2. データベースを段階的に設計する1
  3. 初級データベースアルゴリズム [I]
  4. エントリーレベルのデータベースアルゴリズム [パート 2]
  5. エントリーレベルのデータベースアルゴリズム [パート 3]

<<:  Cacti パーセンタイル監視アルゴリズム

>>:  エントリーレベルのデータベースアルゴリズム [パート 3]

推薦する

...

エネルギー分野における人工知能の5つの主要な応用

[[435080]]エネルギー分野における AI の革新と進歩により、企業がエネルギーを生産、販売、...

OpenAI: 大規模ニューラルネットワークをトレーニングするための 4 つの基本手法

この記事はLeiphone.comから転載したものです。転載する場合は、Leiphone.com公式...

Minecraft でニューラル ネットワークを構築し、操作プロセスを明確に表示する | オープン ソース

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

ハイブリッドクラウドプラットフォームがデータの障壁を打ち破り、人工知能がデータの価値を活性化

デジタル経済の時代において、企業の将来の競争力を形成する鍵として、データの価値は企業からますます注目...

ブースティング原理に基づく深層残差ニューラルネットワークのトレーニング

1. 背景1.1 ブースティングブースティング[1]は、アンサンブルモデルを訓練するための古典的な手...

自然言語処理にディープラーニングを使用するにはどうすればよいでしょうか?練習チェックリストはこちら

[[198324]]導入この記事は、自然言語処理 (NLP) にニューラル ネットワークを使用する方...

ビッグモデルが明らかに:ユーザーレビューから金脈を抽出する方法

著者 | 崔昊レビュー | Chonglouまとめこの論文では、大規模な言語モデルと LangCha...

...

Googleが生成AIをオンラインショッピングに適用、実在のモデルが高精度な仮想衣装着せ替えを実現

グーグルは6月15日、オンラインショッピングツールに新たな生成AI技術を導入すると発表した。この技術...

たった5秒でNeRFをトレーニング? ! Nvidia の新技術は Google の研究者の手に負えない | オープンソース

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...

機械学習における欠損値に対処する9つの方法

データサイエンスはデータに関するものです。これは、あらゆるデータ サイエンスや機械学習プロジェクトの...

触覚を感知し、自己治癒するロボットが現実になりつつある

人間の皮膚は柔軟性があり、触り心地がよく、自己治癒力があるため、複製するのが難しいです。しかし、科学...

機械学習における不均衡なクラスに対処するための 5 つの戦略

クラスの不均衡: 希少疾患の機械学習データセット(陽性が約 8%)があるとします。この場合、トレーニ...

ARMの機能によりIBMの包括的なAI自動化ポートフォリオが強化される

Turbonomic の買収計画により、IBM はビジネスと IT 全体にわたって人工知能の自動化機...