標籤:
一個小問題引發的思考
隨機產生20個不重複A-Z的字串,並且順序排列
題目挺簡單要注意幾個點,一 :A-Z的產生 二 : 隨機數 三 :不重複, 順序排列
A-Z的產生:利用ascii碼錶產生字母 //確定A-Z的 ascii碼錶 (65-90)
i=65
char c=(char) i;//c即為"A"
再利用隨機數產生 不同的字串
int i=new Random().nextInt(26)+65;
20個不重複的,迴圈確定個數,set儲存不重複的對象集合
while(true){ int i=new Random().nextInt(26)+65; char c=(char) i; if(set.size()<=20){ set.add(c); } else{ break; }}
最後一步:順序儲存,只需要set集合使用treeSet就可,treeSet是根據對象實現comparable介面按順序儲存對象。
完整例子
public static void main(String[] args) { //確定A-Z的 ascii碼錶 (65-90) TreeSet<Character> set =new TreeSet<Character>(); while(true){ int i=new Random().nextInt(26)+65; char c=(char) i; if(set.size()<=20){ set.add(c); } else{ break; } } for(Iterator<Character> i=set.iterator();i.hasNext();){ char c= i.next(); System.out.println(c); } }
上述只是一個很簡單的小問題,但有兩個問題可以深入探討下
一:隨機數
java產生的隨機數是偽隨機數,即不是真正的隨機,只是按照一定的規則類比出來的。
java中產生隨機數有兩種方法 一種就是開始上面實現的隨機數 int i=new Random().nextInt(26) 產生一個0-25的實際整數
另一種則是 Math.random() 產生一個0-1的浮點數
這兩種的區別
先看 Math.random() 的源碼
private static Random randomNumberGenerator; private static synchronized Random initRNG() { Random rnd = randomNumberGenerator; return (rnd == null) ? (randomNumberGenerator = new Random()) : rnd; } public static double random() { Random rnd = randomNumberGenerator; if (rnd == null) rnd = initRNG(); return rnd.nextDouble(); }
簡單的說,Math.random() 還是調用了 random對象的 nextDouble()方法,只不過random對象是靜態,單一的,上鎖的random對象
接下來看 nextDouble()方法,nextDouble()調用了next()方法,值得說下的是,nextInt()方法之調用了一次next(),速度會比nextDouble()快一丟丟
public double nextDouble() { return (((long)(next(26)) << 27) + next(27)) / (double)(1L << 53); }
接下來繼續看next()方法, next()中有一個很重要的屬性 oldseed,所有運算結果都是根據它產生,而oldseed是怎麼產生的
protected int next(int bits) { long oldseed, nextseed; AtomicLong seed = this.seed; do { oldseed = seed.get(); nextseed = (oldseed * multiplier + addend) & mask; } while (!seed.compareAndSet(oldseed, nextseed)); return (int)(nextseed >>> (48 - bits)); }
又下面可以知道.oldseed是由幾個常數 加系統時間來運算確定的 ,所以呢java隨機數不是真隨機只是個偽隨機,並且不是很安全,因為很容易被算是隨機值,但是可以用java.security.SecureRandom,這個更安全,因為重寫了next()方法。
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; } } private static final AtomicLong seedUniquifier = new AtomicLong(8682522807148012L);
最後:http://blog.csdn.net/ultrani/article/details/7818082 這邊博文的作者寫的更清晰,也更深入的說明random函數演算法的原理,有興趣可以去看下
一個小問題引發的思考