封装好的工具类
/*** 随机工具** @author cc* @date /5/18*/public class RandomUtil {private static final int MAX_WEIGHT = 1;/*** 权重随机算法* 比如传入weightArray={1D,2D,3D,4D} 那么100W次结果返回下标0,1,2,3的概率应为10%,20%,30%,40%* 比如传入weightArray={1D,2D} 那么100W次结果返回下标0,1的概率应为33.33%,66.67%* @param weightArray 权重源数组,不能为空* @return 权重数组下标*/public static int weightWinning(double[] weightArray) {if (weightArray.length == 0) {return -1;}// hutooldouble randomDouble = cn.hutool.core.util.RandomUtil.randomDouble(MAX_WEIGHT);// or java random// double randomDouble = new Random().nextDouble()double sum = 0D;for (double data : weightArray) {sum += data;}int index = 0;double curSum = 0D;for (double data : weightArray) {if (randomDouble < curSum + data / sum) {return index;} else {curSum += data / sum;index++;}}return index;}}
原理
我来拿具体的实例来说weightArray={1,2,3,4}来说
randomDouble 取到的是大约等于0小于1的小数,比如这次的随机结果是0.38...,那么返回的本次下标是如何实现的呢
我们把weightArray={1,2,3,4}将线段长度为1的线段等权划分出来4分,下标为0段长为0.1,范围是[0~0.1)一次类推下标1为[0.1~0.3)。。总结来说0~0.1,0.1~0.3,0.3~0.6,0.6~1.0 那么本次0.38坐落在下标为2的线段中,返回结果为2。
这个思想就是想象把一块飞盘按权重划分为不同区域的位置,randomDouble坐落在哪个位置就返回什么结果。
测试
100W次的结果
注意
randomDouble 我用的是hutool工具包里单例实现的,尽量避免java实例获取