乱数のシードを理解する
4352 ワード
まず、コンピュータは絶対的な乱数を生成してはいけないことを知りたいです.疑似乱数しか生成できません.偽とは規則的という意味です.疑似乱数とは、コンピュータによって生成される乱数に規則があります.
コンピューターはどうやって乱数を発生しますか?
もちろんアルゴリズムによってです.このアルゴリズムはマッピング関係があります.私が1に入れると、彼は特定の数を出します.
このアルゴリズムをブラックボックスと見なして、数を入れたら、特定の数が出てきます.この数を次の種として入れます.
システムが乱数を実現するのは、現在のシステム時間を入れることです.毎回違っていますので、実現できます.
でも、毎回同じ種を入れたら、ランダムに数列を作っても同じです.
リストのサイズがSHUFFLE_より小さい場合THRESHOLD(5)またはlistはRandomAccessインターフェースを実現すると、list内の要素の位置を直接交換します.具体的な交換戦略は以下の通りです.
リストのsizeをnとし、n-1位から、そのビットの要素を前のビット(ランダムに得られた)要素と交換し、1位が終わるまで.
使用する関数:
この時まずやるべきことはリストを行列に変換することです.これはRandomAccessと関係があります.
RandomAccessは、istの実現クラスが急速にランダムアクセス(一般的にO(1)をサポートするかどうかを識別するために使用され、例えばAraryListはRandomAccessインターフェースを実現し、ランダムに一つの要素(get(i)にアクセスするのにかかる時間の複雑さはO(1)であり、LinkdListはこのインターフェースを実現していないので、ランダムな要素の時間の複雑さはO(最悪の場合)である.したがって、listを遍歴する際に、まずRandomAccessインターフェースが実現されたかどうかを判断し、データ構造の違いに応じて、まず対応する処理を行い、O(n 2)が現れる時間の複雑さを回避する.
shuffle()のelseコードセグメントでは、まずRandomAccessインターフェースが実現されていないリストを配列に変換し、その後交換戦略を実行して、O(n 2)の時間の複雑さを避ける.
コンピューターはどうやって乱数を発生しますか?
もちろんアルゴリズムによってです.このアルゴリズムはマッピング関係があります.私が1に入れると、彼は特定の数を出します.
RAND_SEED=(RAND_SEED*123+59)%65536;
これはあるシステムの乱数アルゴリズムです.このアルゴリズムをブラックボックスと見なして、数を入れたら、特定の数が出てきます.この数を次の種として入れます.
システムが乱数を実現するのは、現在のシステム時間を入れることです.毎回違っていますので、実現できます.
でも、毎回同じ種を入れたら、ランダムに数列を作っても同じです.
public class RandomTest {
public static void main(String[] args) {
Random random = new Random();
random.setSeed(1);
System.out.println(random.nextInt(10));
System.out.println(random.nextInt(10));
random.setSeed(1);
System.out.println(random.nextInt(10));
System.out.println(random.nextInt(10));
}
}
出力5
8
5
8
Collection shuffleソースpublic static void shuffle(List> list) {
Random rnd = r;
if (rnd == null)
r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}
public Random() {
this(seedUniquifier() ^ System.nanoTime()); //
}
private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
public static void shuffle(List> list, Random rnd) {
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i));
} else {
Object arr[] = list.toArray();
// Shuffle array
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i));
// Dump array back into list
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
ListIterator it = list.listIterator();
for (int i=0; i
一、まずシャッフルするリストの属性を判断します.リストのsizeとRandomAccessインターフェースを実現するかどうかです.リストのサイズがSHUFFLE_より小さい場合THRESHOLD(5)またはlistはRandomAccessインターフェースを実現すると、list内の要素の位置を直接交換します.具体的な交換戦略は以下の通りです.
リストのsizeをnとし、n-1位から、そのビットの要素を前のビット(ランダムに得られた)要素と交換し、1位が終わるまで.
使用する関数:
public static void swap(List> list, int i, int j) {
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
final List l = list;
l.set(i, l.set(j, l.get(i))); // j i
}
E set(int index, E element)
/**
* Replaces the element at the specified position in this list with the
* specified element (optional operation).
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
*/
E set(int index, E element)
E set(int index,E element)のいずれかの実装public E set(int index, E element) {
try {
ListIterator e = listIterator(index);
E oldVal = e.next();
e.set(element);
return oldVal; // index element,
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
二、listがRandomAccessインターフェースを実現していない場合、長さはSHUFFLE_より大きい.THRESHLD(5)この時まずやるべきことはリストを行列に変換することです.これはRandomAccessと関係があります.
RandomAccessは、istの実現クラスが急速にランダムアクセス(一般的にO(1)をサポートするかどうかを識別するために使用され、例えばAraryListはRandomAccessインターフェースを実現し、ランダムに一つの要素(get(i)にアクセスするのにかかる時間の複雑さはO(1)であり、LinkdListはこのインターフェースを実現していないので、ランダムな要素の時間の複雑さはO(最悪の場合)である.したがって、listを遍歴する際に、まずRandomAccessインターフェースが実現されたかどうかを判断し、データ構造の違いに応じて、まず対応する処理を行い、O(n 2)が現れる時間の複雑さを回避する.
shuffle()のelseコードセグメントでは、まずRandomAccessインターフェースが実現されていないリストを配列に変換し、その後交換戦略を実行して、O(n 2)の時間の複雑さを避ける.