乱数のシードを理解する

4352 ワード

まず、コンピュータは絶対的な乱数を生成してはいけないことを知りたいです.疑似乱数しか生成できません.偽とは規則的という意味です.疑似乱数とは、コンピュータによって生成される乱数に規則があります.
コンピューターはどうやって乱数を発生しますか?
もちろんアルゴリズムによってです.このアルゴリズムはマッピング関係があります.私が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)の時間の複雑さを避ける.