實際場景中,經常要從多個選項中隨機選擇一個,不過,不同選項經常有不同的權重。
/** * Created by xc on 2019/11/23 * 帶權重的隨機選擇 */ public class Test { public static void main(String[] args) { Pair[] options = new Pair[]{new Pair("first", 3.3), new Pair("second", 3.3), new Pair("third", 3.3)}; WeightRandom rnd = new WeightRandom(options); for (int i = 0; i < 10; i++) { System.out.print(rnd.nextItem() + " "); } } }
/** * Created by xc on 2019/11/25 * 表示選項和權重的類Pair */ public class Pair { Object item; double weight; public Pair(Object item, double weight) { this.item = item; this.weight = weight; } public Object getItem() { return item; } public double getWeight() { return weight; } }
/** * Created by xc on 2019/11/25 * 代碼清單7-9 帶權重的選擇WeightRandom */ public class WeightRandom { private Pair[] options; private double[] cumulativeProbabilities; private Random rnd; public WeightRandom(Pair[] options) { this.options = options; this.rnd = new Random(); prepare(); } /** * prepare()方法計算每個選項的累計概率,保存在數組cumulativeProbabilities中 */ private void prepare() { int weights = 0; for (Pair pair : options) { weights += pair.getWeight(); } cumulativeProbabilities = new double[options.length]; int sum = 0; for (int i = 0; i < options.length; i++) { sum += options[i].getWeight(); cumulativeProbabilities[i] = sum / (double) weights; } } /** * nextItem()方法根據權重隨機選擇一個,具體就是,首先生成一個0~1的數, * 然后使用二分查找,如果沒找到,返回結果是-(插入點)-1,所以-index-1就是插入點,插入點的位置就對應選項的索引。 * @return */ public Object nextItem() { double randomValue = rnd.nextDouble(); int index = Arrays.binarySearch(cumulativeProbabilities, randomValue); if (index < 0) { index = -index - 1; } return options[index].getItem(); } }