java產生抽樣隨機數的多種演算法_java

來源:互聯網
上載者:User

本章先講解Java隨機數的幾種產生方式,然後通過樣本對其進行示範。

概述:

這裡你是不是會說,產生隨機數有什麼難的?不就是直接使用Java封裝好了的random就行了嗎?當然對於一般情況下是OK的,而且本文要說明的這些演算法也是基於這個random庫函數的。

本文主要是針對抽樣這一行為進行的,而抽樣本身有一個隱含的規則就是不要有重複資料。好了,有了這些說明。你可以先嘗試著用一些自己的想法來實現不重複地產生隨機數。

演算法嘗試:

一些好的演算法出現,往往伴隨著一些不那麼好的演算法。但是對於效果不太好的演算法,它們普遍有一個共性,方便理解和實現。下面是通過一個循序漸進的方式來作一個簡單地說明。

第一次嘗試:樸素隨機演算法

這個演算法很好理解,就是隨機!每一次產生一個隨機數,並加入集合。 

 private void simpleRandom(int start, int end, int count) {     System.out.println("樸素隨機演算法:");     StringBuffer buffer = new StringBuffer();     for (int i = 0; i < count; i++) {       int random = NumberUtils.randomInteger(start, end);       buffer.append(i == 0 ? ("[" + random) : (", " + random));     }     buffer.append("]");     System.out.println(buffer);   } 

第二次嘗試:檢查存在性隨機演算法

我們知道上面的方法有一個問題,就是可能會有重複資料。於是,我們就想到,在產生一個隨機數的時候進行檢查一下這個數是不是已經存在了,如果存在了就重建。

private void checkRandom(int start, int end, int count) {     System.out.println("檢查存在性隨機演算法:");     StringBuffer buffer = new StringBuffer();     List<Integer> save = new ArrayList<>();     for (int i = 0; i < count; i++) {       int random = NumberUtils.randomInteger(start, end);       if (exits(save, random)) {         i--;         continue;       }              save.add(random);       buffer.append(i == 0 ? ("[" + random) : (", " + random));     }     buffer.append("]");     System.out.println(buffer);   } 

第三次嘗試:元素移除隨機演算法

上面的演算法已經解決了資料重複的問題。不過,有一個很糟糕的問題就是可能我們要花費很長的時間來產生抽樣隨機數(這個要看臉了。。。。)。

不過,這裡我們有了新想法。那就是在一個集合中去隨機一個數,當這個被選中的時候就remove掉,那麼下次再隨機的時候是不是就不會再隨機到這個數了?這樣就很好地解決了隨機數的重複問題。代碼如下:

 private void removeRandom(int start, int end, int count) {     System.out.println("元素移除隨機演算法:");     StringBuffer buffer = new StringBuffer();     List<Integer> numbers = initList(start, end);     for (int i = 0; i < count; i++) {       int random = NumberUtils.randomInteger(count - i);       buffer.append(i == 0 ? ("[" + numbers.get(random)) : (", " + numbers.get(random)));       numbers.remove(random);     }          buffer.append("]");     System.out.println(buffer);   } 

第四次嘗試:狀態轉移隨機演算法

在我之前的很多部落格中,就有一些是演算法中的狀態轉移過程。而狀態的轉移也是我最喜歡的演算法之一。下面的圖-1中標註了隨機數的取值範圍,序列中的橙色數字是結果中的隨機序列。最下方的序列中有一些虛線的箭頭,代表了狀態的轉移。

圖-1 基於狀態轉移的抽樣隨機數產生演算法

實現代碼:

 private void statusRandom(int start, int end, int count) {     System.out.println("狀態轉移隨機演算法:");     StringBuffer buffer = new StringBuffer();     int[] status = new int[end + 1];     for (int i = 0; i < count; i++) {       int random = NumberUtils.randomInteger(start, end);       System.err.println(random);       if (status[random] == 0) {         buffer.append(i == 0 ? ("[" + random) : (", " + random));         status[random] = random == end ? start : (random + 1); // 不可能有在start之前的數字       } else {         // 狀態轉移         int index = random;         do {           index = status[index];         } while (status[index] != 0);                  buffer.append(i == 0 ? ("[" + index) : (", " + index));         status[index] = index == end ? start : (index + 1); // 不可能有在start之前的數字       }     }          buffer.append("]");     System.out.println(buffer);   } 

第五次嘗試:遞迴Floyd隨機演算法

Floyd演算法說到底也是一種狀態的轉移過程。該演算法會要求輸入一個List或是array來儲存已經確定的隨機數。顧名思義,這裡我會用到遞迴的解法。在遞迴的過程中,我們把第i個隨機數的狀態轉移到了第i-1個隨機身上了。代碼如下:

private List<Integer> simpleFloyd(List<Integer> list, int count, int start, int end) {     if (count == 0) {       return list;     }     list = simpleFloyd(list, count - 1, start, end - 1);     int random = NumberUtils.randomInteger(start, end);     if (list.contains(random)) {       list.add(end);     } else {       list.add(random);     }     return list;   } 

第六次嘗試:迭代Floyd隨機演算法

思路與上面的遞迴Floyd隨機演算法是相似的,不過,這裡我們加入了一個變數來做最佳化。就不需要再去遞迴了。代碼如下:

private List<Integer> iterationFloyd(int start, int end, int count) {     System.out.println("迭代Floyd隨機演算法:");     List<Integer> list = new ArrayList<>();     for (int i = end - count + 1; i < end; i++) {       int random = NumberUtils.randomInteger(start, i);       if (list.contains(random)) {         list.add(i);       } else {         list.add(random);       }     }          return list;   } 

測試結果:

 

圖-2 隨機數產生演算法測試結果

在上面的測試結果中,我們可以很明顯地看出樸素隨機演算法不僅有重複資料,而且還是最耗時的。所以,在抽樣的隨機數產生時,避免使用這一演算法。而在後幾種演算法中,狀態轉移隨機演算法最佳,迭代Floyd隨機演算法次之。這個可以根據個人偏愛來做選擇。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.