前言:应项目中有需求做一个抽奖活动,所以我去看了很多篇文章,取了其中一篇文章,做了修改.达到了我的需求,
思路:
1.先计算权重,然后得到区域,
2.随机一个随机数,判断在哪个区域,就得到相应的奖品
分析:如上图,为了便于计算和理解,可以设置每种奖品的权重分别为1,2,3,4,所以被抽到的概率分别为0.1,0.2,0.3,0.4(本次活动中奖概率为100%)。
先生成一个随机数randomNumber,然后根据随机数所处区域判断奖品:
0 <=randomNumber <0.1 表示抽中一等奖
0.1<=randomNumber<0.3 表示抽中二等奖
0.3<=randomNumber<0.6 表示抽中三等奖
0.6<=randomNumber<1.0 表示抽中四等奖
抽奖实现
奖品实体 Prize.java
public class Prize {
private int id;//奖品id
private String prize_name;//奖品名称
private int prize_amount;//奖品(剩余)数量
private int prize_weight;//奖品权重
//getter、setter
}
这里只考虑最简单的抽奖实现,所以暂时只为奖品设计如上4个字段。
见注释,prize_name表示奖品名称;prize_amount表示奖品数量,即本次抽奖活动计划发放此奖品的数量;prize_weight表示奖品权重,表示奖品被抽到的几率的比重,权重越大,被抽到的几率越大,比如本次砸金蛋活动有4种奖品,权重分别是1、2、3、4、90,总权重是100,那么每种奖品被抽到的几率就是1/100,2/100,3/100,4/100 , 90/100。
核心算法:
/**
* 根据Math.random()产生一个double型的随机数,判断每个奖品出现的概率
* @param prizes 奖品实体集合
* @return random:奖品列表prizes中的序列(prizes中的第random个就是抽中的奖品)
*/
public int getPrizeIndex(List<Prize> prizes) {
int random = -1;
try{
//计算总权重
double sumWeight = 0;
for(Prize p : prizes){
sumWeight += p.getPrize_weight();
}
//产生随机数
double randomNumber;
randomNumber = Math.random();
//根据随机数在所有奖品分布的区域并确定所抽奖品
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;
break;
}
}
}catch(Exception e){
System.out.println("生成抽奖随机数出错,出错原因:" +e.getMessage());
}
return random;
}
抽奖测试:
public static void main(String[] agrs) {
int i = 0;
int[] result=new int[5];
List<Prize> prizes = new ArrayList<Prize>();
Prize p1 = new Prize();
p1.setPrize_name("范冰冰海报");
p1.setPrize_weight(1);//奖品的权重设置成1
p1.setPrize_amount(1);
prizes.add(p1);
Prize p2 = new Prize();
p2.setPrize_name("上海紫园1号别墅");
p2.setPrize_weight(2);//奖品的权重设置成2
p2.setPrize_amount(1);
prizes.add(p2);
Prize p3 = new Prize();
p3.setPrize_name("奥迪a9");
p3.setPrize_weight(3);//奖品的权重设置成3
p3.setPrize_amount(1);
prizes.add(p3);
Prize p4 = new Prize();
p4.setPrize_name("双色球彩票");
p4.setPrize_weight(4);//奖品的权重设置成4
p4.setPrize_amount(1);
prizes.add(p4);
Prize p5 = new Prize();
p5.setPrize_name("谢谢参与");
p5.setPrize_weight(90);//奖品的权重设置成90
p5.setPrize_amount(10000);
prizes.add(p5);
System.out.println("抽奖开始");
for (i = 0; i < 10000; i++)// 打印10000个测试概率的准确性
{
//标记,用来结束死循环
boolean flag=true;
//奖品索引
int selected = 0;
while(flag){
//抽奖
selected=getPrizeIndex(prizes);
if (prizes.get(selected).getPrize_amount()>0) {
flag=false;
}else{
System.out.println(prizes.get(selected).getPrize_name()+"的数量为"+prizes.get(selected).getPrize_amount()+",所以重新抽奖!!");
}
}
//抽到奖品后,奖品-1
prizes.get(selected).setPrize_amount( prizes.get(selected).getPrize_amount()-1);
System.out.println("奖品索引: "+selected);
System.out.println("第"+i+"次抽中的奖品为:"+prizes.get(selected).getPrize_name());
System.out.println(prizes.get(selected).getPrize_name()+"奖品剩余数量:"+prizes.get(selected).getPrize_amount());
result[selected]++;
System.out.println("--------------------------------");
}
System.out.println("抽奖结束");
System.out.println("每种奖品抽到的数量为:");
System.out.println("一等奖:"+result[0]);
System.out.println("二等奖:"+result[1]);
System.out.println("三等奖:"+result[2]);
System.out.println("四等奖:"+result[3]);
System.out.println("五等奖:"+result[4]);
}
尝试抽奖10000次的结果如下:
一等奖:1
二等奖:1
三等奖:1
四等奖:1
五等奖:9996
因为我这里设置前面几个奖项只有1个,所以导致这里最多只能抽中一次,
其实每类奖品获奖次数比例刚好大约为1:2:3:4 : 90,学过概率的你肯定知道抽奖次数越多,
测试结果越准确~~,