私は0から1000までのユニークな乱数を生成したいと思いますが、これは繰り返されません(6は2回現れません)が、それは前のO(N)検索のようなものに頼りませんそれを行うための値。これは可能ですか?
値0〜1000で1001個の整数の配列を初期化し、変数maxを配列の現在の最大インデックス(1000から始まる)に設定します。 0からmaxの間の乱数rを選択し、rの位置の数値をmaxの位置の数値と交換し、現在のmaxの位置の数値を返します。最大値を1減らして続行します。 maxが0の場合、maxを配列のサイズ-1に戻し、配列を再初期化せずに再起動します。
更新:質問に答えたときに自分でこの方法を思いつきましたが、いくつかの調査の後、これは Fisher-Yates Durstenfeld-Fisher-YatesまたはKnuth-Fisher-Yatesとして知られています。説明を理解するのは少し難しいかもしれないので、以下に例を示します(1001の代わりに11個の要素を使用)。
配列はarray [n] = nに初期化された11個の要素から始まり、最大は10から始まります。
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|
+--+--+--+--+--+--+--+--+--+--+--+
^
max
各反復で、乱数rが0〜maxの間で選択され、array [r]とarray [max]が交換され、新しいarray [max]が返され、maxが減少します。
max = 10, r = 3
+--------------------+
v v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2|10| 4| 5| 6| 7| 8| 9| 3|
+--+--+--+--+--+--+--+--+--+--+--+
max = 9, r = 7
+-----+
v v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 1| 2|10| 4| 5| 6| 9| 8| 7: 3|
+--+--+--+--+--+--+--+--+--+--+--+
max = 8, r = 1
+--------------------+
v v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 8| 2|10| 4| 5| 6| 9| 1: 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+
max = 7, r = 5
+-----+
v v
+--+--+--+--+--+--+--+--+--+--+--+
| 0| 8| 2|10| 4| 9| 6| 5: 1| 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+
...
11回の反復後、配列内のすべての数値が選択され、max == 0になり、配列要素がシャッフルされます。
+--+--+--+--+--+--+--+--+--+--+--+
| 4|10| 8| 6| 2| 0| 9| 5| 1| 7| 3|
+--+--+--+--+--+--+--+--+--+--+--+
この時点で、maxは10にリセットでき、プロセスを続行できます。
あなたはこれを行うことができます:
そのため、毎回古い値を検索する必要はありませんが、最初のシャッフルにはO(N)が必要です。しかし、Nilsがコメントで指摘したように、これは償却されたO(1)です。
最大線形フィードバックシフトレジスタ を使用します。
Cの数行で実装可能であり、実行時に2つのテスト/ブランチ、少しの追加、ビットシフトを実行するだけです。それはランダムではありませんが、ほとんどの人をだます。
A Linear Congruential Generator を使用できます。 m
(モジュラス)は、1000より大きい最も近い素数になります。範囲外の数値を取得したら、次の素数を取得します。シーケンスはすべての要素が発生した後にのみ繰り返され、テーブルを使用する必要はありません。ただし、このジェネレーターの欠点に注意してください(ランダム性の欠如を含む)。
Format-Preserving Encryption を使用して、カウンターを暗号化できます。カウンターは0から上に移動するだけで、暗号化では選択したキーを使用して、基数と幅が任意のランダムな値に変換されます。例えば。この質問の例では、基数10、幅3です。
通常、ブロック暗号のブロックサイズは固定です。 64または128ビット。ただし、Format-Preserving Encryptionを使用すると、AESのような標準暗号を使用して、暗号化に堅牢なアルゴリズムを使用して、必要な基数と幅の幅の狭い暗号を作成できます。
衝突が発生しないことが保証されています(暗号化アルゴリズムは1:1マッピングを作成するため)。また、リバーシブル(2ウェイマッピング)であるため、結果の数値を取得して、開始時のカウンター値に戻すことができます。
この手法は、シャッフルされた配列などを保存するためのメモリを必要としません。これは、メモリが限られているシステムで利点となる可能性があります。
AES-FFX は、これを達成するために提案された標準的な方法の1つです。 AES-FFXのアイデアに基づいたいくつかの基本的なPythonコードを試しましたが、完全に準拠しているわけではありませんが、- ここでPythonコードを参照してください 。例えばカウンターをランダムに見える7桁の10進数、または16ビットの数値に暗号化します。基数10、幅3(0から999までの数字を与える)の例は次のとおりです。
000 733
001 374
002 882
003 684
004 593
005 578
006 233
007 811
008 072
009 337
010 119
011 103
012 797
013 257
014 932
015 433
... ...
異なる非繰り返し擬似ランダムシーケンスを取得するには、暗号化キーを変更します。各暗号化キーは、異なる非反復擬似ランダムシーケンスを生成します。
0 ... 1000のような低い数値の場合、すべての数値を含むリストを作成してシャッフルするのは簡単です。ただし、描画する数値のセットが非常に大きい場合、別のエレガントな方法があります。キーと暗号化ハッシュ関数を使用して、擬似ランダムな順列を構築できます。次のC++風の擬似コードの例を参照してください。
unsigned randperm(string key, unsigned bits, unsigned index) {
unsigned half1 = bits / 2;
unsigned half2 = (bits+1) / 2;
unsigned mask1 = (1 << half1) - 1;
unsigned mask2 = (1 << half2) - 1;
for (int round=0; round<5; ++round) {
unsigned temp = (index >> half1);
temp = (temp << 4) + round;
index ^= hash( key + "/" + int2str(temp) ) & mask1;
index = ((index & mask2) << half1) | ((index >> half2) & mask1);
}
return index;
}
ここで、hash
は、文字列を巨大な符号なし整数にマッピングする、任意の疑似ランダム関数です。関数randperm
は、固定キーを想定した0 ... pow(2、bits)-1内のすべての数値の順列です。これは、変数index
を変更するすべてのステップが可逆的であるため、構築から始まります。これは Feistel暗号 に触発されています。
ここで説明する私のXincrolアルゴリズムを使用できます。
http://openpatent.blogspot.co.il/2013/04/xincrol-unique-and-random-number.html
これは、配列、リスト、順列、または重いCPU負荷なしで、ランダムだが一意の数値を生成する純粋なアルゴリズム手法です。
最新バージョンでは、数値の範囲を設定することもできます。たとえば、0-1073741821の範囲で一意の乱数が必要な場合。
私は実際にそれを使用しました
オープンで無料です。試してみる...
これを解決するために配列さえ必要ありません。
ビットマスクとカウンターが必要です。
カウンターをゼロに初期化し、連続する呼び出しで増分します。 XOR擬似乱数を生成するためのビットマスク付きカウンター(起動時にランダムに選択、または固定)。 1000を超える数値を使用できない場合は、9ビットよりも広いビットマスクを使用しないでください。 (つまり、ビットマスクは511を超えない整数です。)
カウンタが1000を超えたら、必ずゼロにリセットしてください。この時点で、必要に応じて別のランダムビットマスクを選択して、同じ番号のセットを異なる順序で生成できます。
最初のソリューションのロジックを使用する、入力したコードを次に示します。私はこれが「言語に依存しない」ことを知っていますが、誰もが迅速で実用的な解決策を探している場合に備えて、これをC#の例として提示したかっただけです。
// Initialize variables
Random RandomClass = new Random();
int RandArrayNum;
int MaxNumber = 10;
int LastNumInArray;
int PickedNumInArray;
int[] OrderedArray = new int[MaxNumber]; // Ordered Array - set
int[] ShuffledArray = new int[MaxNumber]; // Shuffled Array - not set
// Populate the Ordered Array
for (int i = 0; i < MaxNumber; i++)
{
OrderedArray[i] = i;
listBox1.Items.Add(OrderedArray[i]);
}
// Execute the Shuffle
for (int i = MaxNumber - 1; i > 0; i--)
{
RandArrayNum = RandomClass.Next(i + 1); // Save random #
ShuffledArray[i] = OrderedArray[RandArrayNum]; // Populting the array in reverse
LastNumInArray = OrderedArray[i]; // Save Last Number in Test array
PickedNumInArray = OrderedArray[RandArrayNum]; // Save Picked Random #
OrderedArray[i] = PickedNumInArray; // The number is now moved to the back end
OrderedArray[RandArrayNum] = LastNumInArray; // The picked number is moved into position
}
for (int i = 0; i < MaxNumber; i++)
{
listBox2.Items.Add(ShuffledArray[i]);
}
このメソッドは、制限がhighであり、少数の乱数のみを生成する場合に適切になります。
#!/usr/bin/Perl
($top, $n) = @ARGV; # generate $n integer numbers in [0, $top)
$last = -1;
for $i (0 .. $n-1) {
$range = $top - $n + $i - $last;
$r = 1 - Rand(1.0)**(1 / ($n - $i));
$last += int($r * $range + 1);
print "$last ($r)\n";
}
番号は昇順で生成されますが、その後シャッフルできることに注意してください。
良い 疑似乱数ジェネレーター を10ビットで使用し、1001から1023を捨てて0から1000を残すことができます。
here から、10ビットPRNGの設計を取得します。
10ビット、フィードバック多項式x ^ 10 + x ^ 7 + 1(期間1023)
ガロアLFSRを使用して高速コードを取得する
Linear congruential generator が最も簡単な解決策だと思います。
a、cおよびm値
PSこのメソッドについてはすでに言及しましたが、投稿には定数値に関する誤った仮定があります。以下の定数はあなたの場合にうまく機能するはずです
あなたの場合、a = 1002
、c = 757
、m = 1001
を使用できます
X = (1002 * X + 757) mod 1001
public static int[] randN(int n, int min, int max)
{
if (max <= min)
throw new ArgumentException("Max need to be greater than Min");
if (max - min < n)
throw new ArgumentException("Range needs to be longer than N");
var r = new Random();
HashSet<int> set = new HashSet<int>();
while (set.Count < n)
{
var i = r.Next(max - min) + min;
if (!set.Contains(i))
set.Add(i);
}
return set.ToArray();
}
N非反復乱数は、必要に応じてO(n)複雑度になります。
注:ランダムは、スレッドセーフが適用された静的でなければなりません。
質問 と上限Nの間のK個の非反復整数のリストを効率的に生成するにはどうすればよいですか は重複としてリンクされています-そして、O(1)生成された乱数ごとに(O(n)起動コストなしで)受け入れられた答えの簡単な調整があります。
初期化された配列を使用する代わりに、整数から整数への空の順序なしマップを作成します(空の順序付きマップは要素ごとにO(log k)を取ります)。最大の場合は、最大を1000に設定します。
初期化された配列を使用する場合と比較した唯一の違いは、要素の初期化が延期/スキップされることですが、同じPRNGからまったく同じ数を生成します。
シャッフルされたリストを何度も何度も繰り返して、もう一度シャッフルするために最初からやり直すたびにO(n)
の遅延を発生させたくない場合、次のようにします。
0〜1000の2つのリストAとBを作成し、2n
スペースを取ります。
Fisher-Yatesを使用してリストAをシャッフルするには、n
時間かかります。
数字を描くときは、もう一方のリストで1ステップのFisher-Yatesシャッフルを行います。
カーソルがリストの最後にあるとき、他のリストに切り替えます。
前処理
cursor = 0
selector = A
other = B
shuffle(A)
描画
temp = selector[cursor]
swap(other[cursor], other[random])
if cursor == N
then swap(selector, other); cursor = 0
else cursor = cursor + 1
return temp
試してみることのできるサンプルCOBOLコードを次に示します。
。
IDENTIFICATION DIVISION.
PROGRAM-ID. RANDGEN as "ConsoleApplication2.RANDGEN".
AUTHOR. Myron D Denson.
DATE-COMPILED.
* **************************************************************
* SUBROUTINE TO GENERATE RANDOM NUMBERS THAT ARE GREATER THAN
* ZERO AND LESS OR EQUAL TO THE RANDOM NUMBERS NEEDED WITH NO
* DUPLICATIONS. (CALL "RANDGEN" USING RANDGEN-AREA.)
*
* CALLING PROGRAM MUST HAVE A COMPARABLE LINKAGE SECTION
* AND SET 3 VARIABLES PRIOR TO THE FIRST CALL IN RANDGEN-AREA
*
* FORMULA CYCLES THROUGH EVERY NUMBER OF 2X2 ONLY ONCE.
* RANDOM-NUMBERS FROM 1 TO RANDOM-NUMBERS-NEEDED ARE CREATED
* AND PASSED BACK TO YOU.
*
* RULES TO USE RANDGEN:
*
* RANDOM-NUMBERS-NEEDED > ZERO
*
* COUNT-OF-ACCESSES MUST = ZERO FIRST TIME CALLED.
*
* RANDOM-NUMBER = ZERO, WILL BUILD A SEED FOR YOU
* WHEN COUNT-OF-ACCESSES IS ALSO = 0
*
* RANDOM-NUMBER NOT = ZERO, WILL BE NEXT SEED FOR RANDGEN
* (RANDOM-NUMBER MUST BE <= RANDOM-NUMBERS-NEEDED)
*
* YOU CAN PASS RANDGEN YOUR OWN RANDOM-NUMBER SEED
* THE FIRST TIME YOU USE RANDGEN.
*
* BY PLACING A NUMBER IN RANDOM-NUMBER FIELD
* THAT FOLLOWES THESE SIMPLE RULES:
* IF COUNT-OF-ACCESSES = ZERO AND
* RANDOM-NUMBER > ZERO AND
* RANDOM-NUMBER <= RANDOM-NUMBERS-NEEDED
*
* YOU CAN LET RANDGEN BUILD A SEED FOR YOU
*
* THAT FOLLOWES THESE SIMPLE RULES:
* IF COUNT-OF-ACCESSES = ZERO AND
* RANDOM-NUMBER = ZERO AND
* RANDOM-NUMBER-NEEDED > ZERO
*
* TO INSURING A DIFFERENT PATTERN OF RANDOM NUMBERS
* A LOW-RANGE AND HIGH-RANGE IS USED TO BUILD
* RANDOM NUMBERS.
* COMPUTE LOW-RANGE =
* ((SECONDS * HOURS * MINUTES * MS) / 3).
* A HIGH-RANGE = RANDOM-NUMBERS-NEEDED + LOW-RANGE
* AFTER RANDOM-NUMBER-BUILT IS CREATED
* AND IS BETWEEN LOW AND HIGH RANGE
* RANDUM-NUMBER = RANDOM-NUMBER-BUILT - LOW-RANGE
*
* **************************************************************
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
DATA DIVISION.
FILE SECTION.
WORKING-STORAGE SECTION.
01 WORK-AREA.
05 X2-POWER PIC 9 VALUE 2.
05 2X2 PIC 9(12) VALUE 2 COMP-3.
05 RANDOM-NUMBER-BUILT PIC 9(12) COMP.
05 FIRST-PART PIC 9(12) COMP.
05 WORKING-NUMBER PIC 9(12) COMP.
05 LOW-RANGE PIC 9(12) VALUE ZERO.
05 HIGH-RANGE PIC 9(12) VALUE ZERO.
05 YOU-PROVIDE-SEED PIC X VALUE SPACE.
05 RUN-AGAIN PIC X VALUE SPACE.
05 PAUSE-FOR-A-SECOND PIC X VALUE SPACE.
01 SEED-TIME.
05 HOURS PIC 99.
05 MINUTES PIC 99.
05 SECONDS PIC 99.
05 MS PIC 99.
*
* LINKAGE SECTION.
* Not used during testing
01 RANDGEN-AREA.
05 COUNT-OF-ACCESSES PIC 9(12) VALUE ZERO.
05 RANDOM-NUMBERS-NEEDED PIC 9(12) VALUE ZERO.
05 RANDOM-NUMBER PIC 9(12) VALUE ZERO.
05 RANDOM-MSG PIC X(60) VALUE SPACE.
*
* PROCEDURE DIVISION USING RANDGEN-AREA.
* Not used during testing
*
PROCEDURE DIVISION.
100-RANDGEN-EDIT-Housekeeping.
MOVE SPACE TO RANDOM-MSG.
IF RANDOM-NUMBERS-NEEDED = ZERO
DISPLAY 'RANDOM-NUMBERS-NEEDED ' NO ADVANCING
ACCEPT RANDOM-NUMBERS-NEEDED.
IF RANDOM-NUMBERS-NEEDED NOT NUMERIC
MOVE 'RANDOM-NUMBERS-NEEDED NOT NUMERIC' TO RANDOM-MSG
GO TO 900-EXIT-RANDGEN.
IF RANDOM-NUMBERS-NEEDED = ZERO
MOVE 'RANDOM-NUMBERS-NEEDED = ZERO' TO RANDOM-MSG
GO TO 900-EXIT-RANDGEN.
IF COUNT-OF-ACCESSES NOT NUMERIC
MOVE 'COUNT-OF-ACCESSES NOT NUMERIC' TO RANDOM-MSG
GO TO 900-EXIT-RANDGEN.
IF COUNT-OF-ACCESSES GREATER THAN RANDOM-NUMBERS-NEEDED
MOVE 'COUNT-OF-ACCESSES > THAT RANDOM-NUMBERS-NEEDED'
TO RANDOM-MSG
GO TO 900-EXIT-RANDGEN.
IF YOU-PROVIDE-SEED = SPACE AND RANDOM-NUMBER = ZERO
DISPLAY 'DO YOU WANT TO PROVIDE SEED Y OR N: '
NO ADVANCING
ACCEPT YOU-PROVIDE-SEED.
IF RANDOM-NUMBER = ZERO AND
(YOU-PROVIDE-SEED = 'Y' OR 'y')
DISPLAY 'ENTER SEED ' NO ADVANCING
ACCEPT RANDOM-NUMBER.
IF RANDOM-NUMBER NOT NUMERIC
MOVE 'RANDOM-NUMBER NOT NUMERIC' TO RANDOM-MSG
GO TO 900-EXIT-RANDGEN.
200-RANDGEN-DATA-Housekeeping.
MOVE FUNCTION CURRENT-DATE (9:8) TO SEED-TIME.
IF COUNT-OF-ACCESSES = ZERO
COMPUTE LOW-RANGE =
((SECONDS * HOURS * MINUTES * MS) / 3).
COMPUTE RANDOM-NUMBER-BUILT = RANDOM-NUMBER + LOW-RANGE.
COMPUTE HIGH-RANGE = RANDOM-NUMBERS-NEEDED + LOW-RANGE.
MOVE X2-POWER TO 2X2.
300-SET-2X2-DIVISOR.
IF 2X2 < (HIGH-RANGE + 1)
COMPUTE 2X2 = 2X2 * X2-POWER
GO TO 300-SET-2X2-DIVISOR.
* *********************************************************
* IF FIRST TIME THROUGH AND YOU WANT TO BUILD A SEED. *
* *********************************************************
IF COUNT-OF-ACCESSES = ZERO AND RANDOM-NUMBER = ZERO
COMPUTE RANDOM-NUMBER-BUILT =
((SECONDS * HOURS * MINUTES * MS) + HIGH-RANGE).
IF COUNT-OF-ACCESSES = ZERO
DISPLAY 'SEED TIME ' SEED-TIME
' RANDOM-NUMBER-BUILT ' RANDOM-NUMBER-BUILT
' LOW-RANGE ' LOW-RANGE.
* *********************************************
* END OF BUILDING A SEED IF YOU WANTED TO *
* *********************************************
* ***************************************************
* THIS PROCESS IS WHERE THE RANDOM-NUMBER IS BUILT *
* ***************************************************
400-RANDGEN-FORMULA.
COMPUTE FIRST-PART = (5 * RANDOM-NUMBER-BUILT) + 7.
DIVIDE FIRST-PART BY 2X2 GIVING WORKING-NUMBER
REMAINDER RANDOM-NUMBER-BUILT.
IF RANDOM-NUMBER-BUILT > LOW-RANGE AND
RANDOM-NUMBER-BUILT < (HIGH-RANGE + 1)
GO TO 600-RANDGEN-CLEANUP.
GO TO 400-RANDGEN-FORMULA.
* *********************************************
* GOOD RANDOM NUMBER HAS BEEN BUILT *
* *********************************************
600-RANDGEN-CLEANUP.
ADD 1 TO COUNT-OF-ACCESSES.
COMPUTE RANDOM-NUMBER =
RANDOM-NUMBER-BUILT - LOW-RANGE.
* *******************************************************
* THE NEXT 3 LINE OF CODE ARE FOR TESTING ON CONSOLE *
* *******************************************************
DISPLAY RANDOM-NUMBER.
IF COUNT-OF-ACCESSES < RANDOM-NUMBERS-NEEDED
GO TO 100-RANDGEN-EDIT-Housekeeping.
900-EXIT-RANDGEN.
IF RANDOM-MSG NOT = SPACE
DISPLAY 'RANDOM-MSG: ' RANDOM-MSG.
MOVE ZERO TO COUNT-OF-ACCESSES RANDOM-NUMBERS-NEEDED RANDOM-NUMBER.
MOVE SPACE TO YOU-PROVIDE-SEED RUN-AGAIN.
DISPLAY 'RUN AGAIN Y OR N '
NO ADVANCING.
ACCEPT RUN-AGAIN.
IF (RUN-AGAIN = 'Y' OR 'y')
GO TO 100-RANDGEN-EDIT-Housekeeping.
ACCEPT PAUSE-FOR-A-SECOND.
GOBACK.
別の可能性:
フラグの配列を使用できます。そして、それがすでに選択されている場合、次のものを取ります。
ただし、1000回の呼び出し後は注意してください。関数は終了しないため、安全対策を講じる必要があります。
Nが1000より大きく、K個のランダムサンプルを描画する必要がある場合、これまでのサンプルを含むセットを使用できます。描画ごとに 拒否サンプリング を使用します。これは「ほぼ」O(1)操作になるため、合計実行時間はほぼO(K)です。 _ O(N)ストレージ付き。
このアルゴリズムは、KがNに「近い」場合に衝突します。これは、実行時間がO(K)よりもはるかに悪いことを意味します。単純な修正方法は、ロジックを逆にして、K> N/2の場合、まだ描画されていないすべてのサンプルの記録を保持することです。各描画は、拒否セットからサンプルを削除します。
拒否サンプリングのもう1つの明らかな問題は、それがO(N)ストレージであるということです。これは、Nが数十億以上の場合、悪いニュースです。ただし、その問題を解決するアルゴリズムがあります。このアルゴリズムは、発明者にちなんでVitterのアルゴリズムと呼ばれます。アルゴリズムは ここ で説明されています。 Gist of Vitterのアルゴリズムでは、各描画の後に、一定のサンプリングを保証する特定の分布を使用してランダムスキップを計算します。
ここでの回答のほとんどは、同じ数値を2回返さないことを保証するものではありません。正しい解決策は次のとおりです。
int nrrand(void) {
static int s = 1;
static int start = -1;
do {
s = (s * 1103515245 + 12345) & 1023;
} while (s >= 1001);
if (start < 0) start = s;
else if (s == start) abort();
return s;
}
制約が適切に指定されているかどうかはわかりません。他の1000の出力の後に値を繰り返すことができると仮定しますが、1000のセットの最後と最初の両方に現れる限り、0の直後に0が続くことを単純に許可します。逆に、繰り返しの間に他の1000個の値があると、その制限を超えて発生した他の値がないため、シーケンスが毎回まったく同じようにリプレイする状況が強制されます。
値を繰り返す前に、少なくとも500個の他の値を常に保証する方法を次に示します。
int nrrand(void) {
static int h[1001];
static int n = -1;
if (n < 0) {
int s = 1;
for (int i = 0; i < 1001; i++) {
do {
s = (s * 1103515245 + 12345) & 1023;
} while (s >= 1001);
/* If we used `i` rather than `s` then our early results would be poorly distributed. */
h[i] = s;
}
n = 0;
}
int i = Rand(500);
if (i != 0) {
i = (n + i) % 1001;
int t = h[i];
h[i] = h[n];
h[n] = t;
}
i = h[n];
n = (n + 1) % 1001;
return i;
}
for i from n−1 downto 1 do
j ← random integer such that 0 ≤ j ≤ i
exchange a[j] and a[i]
実際にはO(n-1)です
これはC#です
public static List<int> FisherYates(int n)
{
List<int> list = new List<int>(Enumerable.Range(0, n));
Random Rand = new Random();
int swap;
int temp;
for (int i = n - 1; i > 0; i--)
{
swap = Rand.Next(i + 1); //.net Rand is not inclusive
if(swap != i) // it can stay in place - if you force a move it is not a uniform shuffle
{
temp = list[i];
list[i] = list[swap];
list[swap] = temp;
}
}
return list;
}
https://stackoverflow.com/a/46807110/8794687 で私の答えをご覧ください
これは、平均時間の複雑さを持つ最も単純なアルゴリズムの1つですO(slogs)、sサンプルサイズを示します。また、O(s)。