根据权重进行抽取的算法应用比较广泛,其中抽奖便是主要用途之一。正好这几天也正在进行抽奖模块的开发,整个抽奖模块涉及到的地方大概有三处,分别是后台进行奖品的添加(同时设置权重和数量),前台根据后台配置生成抽奖队列并根据指令开始抽奖活动,最后一部分是后台统计中奖情况并设置物流状态。本文主要针对前台抽奖算法进行介绍如何根据权重设置每个奖品被抽到的概率。
抽奖算法的核心是根据权重设置随机数出现的概率,在此我将它封装成一个生成随机数的随机类,代码如下:
/**
* JAVA 返回随机数,并根据概率、比率
*
*/
public class MathRandom {
private static Log logger = LogFactory.getLog(MathRandom.class);
/**
* Math.random()产生一个double型的随机数,判断一下 每个奖品出现的概率
*
* @return int
*
*/
public int PercentageRandom(List<RewardPrize> prizes) {
DecimalFormat df = new DecimalFormat("######0.00");
int random = -2;
try{
double sumWeight = 0;
//计算总权重
for(RewardPrize rp_1 : prizes){
sumWeight += rp_1.getPrize_weight();
}
double randomNumber;
randomNumber = Math.random();
System.out.println("randomNumber是:" + randomNumber);
double d1 = 0;
double d2 = 0;
for(int i=0;i<prizes.size();i++){
d2 += Double.parseDouble(String.valueOf(prizes.get(i).getPrize_weight()))/sumWeight;
if(i==0){
d1 = 0;
}else{
d1 +=Double.parseDouble(String.valueOf(prizes.get(i-1).getPrize_weight()))/sumWeight;
}
if(randomNumber >= d1 && randomNumber <= d2){
random = i;
System.out.println("d1是:" + d1);
System.out.println("d2是:" + d2);
break;
}
}
}catch(Exception e){
System.out.println(e.getMessage());
logger.error("生成抽奖随机数出错,出错原因:" + e.getMessage());
random = -1;
}
return random;
}
/**
* 测试主程序
*
* @param agrs
*/
public static void main(String[] agrs) {
int i = 0;
MathRandom a = new MathRandom();
List<RewardPrize> prizes = new ArrayList();
for(int m=0;m<100;m++){
RewardPrize rp = new RewardPrize();
rp.setPrize_amount(10);//每个奖品数量设置10个
rp.setPrize_weight(1);//每个奖品的权重都设置成1,也就是每个奖品被抽到的概率相同(可根据情况自行设置权重)
prizes.add(rp);
}
for (i = 0; i <= 100; i++)// 打印100个测试概率的准确性
{
System.out.println(a.PercentageRandom(prizes));
}
}
}
简单介绍一下上面的代码含义,首先计算出待选奖品的总权重,这样做的目的是可以随意设置奖品权重,不必再考虑权重之和是否等于100。随机规则是首先生成一个随机数randomNumber(生成的随机数位于0到1的左开右闭区间),然后分别计算出当前奖品前前面所有有奖品(不包括当前奖品)的概率和d1和当前奖品后面(包括当前奖品)所有奖品的概率和d2,然后判断生成的随机数randomNumber是否已处于d1和d2之间,如果处于该区间之内则当前奖品将被抽中。