從0到m-1這m個數中隨機取出n個(n<=m) 要求每個數被取到的可能性相等。
第一個方法是把這m個數丟到一個List里面 然后用nextInt(list.size())來產生隨機數 然后把list里面對應的元素丟到另一個數組或者list里面 這個方法本來是不錯的 但要注意的是 為了保證每個元素取到的概率相等 需要每取出一個元素 就把它從list里面刪除 原因就不解釋了 簡單的概率問題。但眾所周知的是 list的remove(int index)方法 效率並不高 尤其是當m和n很大的時候 每一次調用remove ArrayList都需要進行數組的copy 而LinkedList需要進行鏈表的遍歷。
所以再考慮這個問題,用數組來儲存這m個數是很好的 而且其實我們並不需要知道到底哪些下標的元素被選中了 第一個方法的效率低下的原因在於 nextInt(int i)這個方法是從0 到i-1隨機生成整數 這里要求0到i-1是連續的i個整數 而我們選取了一個數之后 為了滿足連續整數的條件 就要把這個數刪去 而頻繁刪除的效率是低下的 所以換一種思路 不采用刪除 而采用交換
第二個方法 比如0-99這100個數字 從小到大放在一個數組里面 現在要選10個 我們只需要隨機打亂這個數組 然后選取前10個元素就好 隨機打亂的方法就是 從數組頭元素開始 每次產生一個隨機數n 然后交換這兩個數 而且只需要交換十次就夠了 因為我們並不取下標超過10后面的數字
import java.util.Random; public class Rand { public static void randSelect(int[] nums, int n) { Random rand = new Random(); for(int i = 0; i < n; i ++){ swap(nums , i, rand.nextInt(nums.length-i)+i); } } public static void swap(int[] nums, int m , int n){ int temp = nums[n]; nums[n] = nums[m]; nums[m] = temp; } public static void main(String[] args) { int[] nums = new int[100]; for(int i = 0;i < 100;i++){ nums[i]=i; } randSelect(nums,10); for(int i = 0;i < 10; i ++){ System.out.println(nums[i]); } } } /*output : 27 79 30 58 41 54 75 18 26 5 */
