有抽奖自然就有三六九等,自然又是金字塔模式。下面贴出我的demo代码,然后一一解答。文章尾部有我的参考链接,大部分代码来源于他,我只是稍微优化。
import java.util.ArrayList;
import java.util.List;
/**
* Created by liyang on 2017/7/13.
*/
public class PrizeTest {
/**
* 根据Math.random()产生一个double型的随机数,判断每个供应商出现的概率
* @param prizes
* @return random:奖品列表prizes中的序列(prizes中的第random个就是抽中的奖品)
*/
public static int getPrizeIndex(List<Prize> prizes) {
int random = -1;
while(random < 0 ) {
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 (d1 <= randomNumber && randomNumber < d2) {
random = i;
break;
}
}
} catch (Exception e) {
System.out.println("出错原因:" + e.getMessage());
}
}
return random;
}
public static void main(String[] agrs) {
int i = 0;
List<Prize> prizes = new ArrayList<Prize>();
Prize p1 = new Prize();
p1.setPrize_name("供应商1");
p1.setPrize_weight(1);//权重设置成1
prizes.add(p1);
Prize p2 = new Prize();
p2.setPrize_name("供应商2");
p2.setPrize_weight(2);//权重设置成2
prizes.add(p2);
Prize p3 = new Prize();
p3.setPrize_name("供应商3");
p3.setPrize_weight(3);//权重设置成3
prizes.add(p3);
Prize p4 = new Prize();
p4.setPrize_name("供应商4");
p4.setPrize_weight(4);//权重设置成4
prizes.add(p4);
int[] result=new int[prizes.size()];
System.out.println("开始.。。");
for (i = 0; i < 100; i++)// 打印100个测试概率的准确性
{
System.out.println("第"+i+"次使用:"+prizes.get(getPrizeIndex(prizes)).getPrize_name());
result[getPrizeIndex(prizes)]++;
System.out.println("--------------------------------");
}
System.out.println("结束。。。");
System.out.println("每家供应商的使用数量为:");
System.out.println("供应商1:"+result[0]);
System.out.println("供应商2:"+result[1]);
System.out.println("供应商3:"+result[2]);
System.out.println("供应商4:"+result[3]);
}
static class Prize{
private String prize_name;//名称
private int prize_weight;//权重
public String getPrize_name() {
return prize_name;
}
public void setPrize_name(String prize_name) {
this.prize_name = prize_name;
}
public int getPrize_weight() {
return prize_weight;
}
public void setPrize_weight(int prize_weight) {
this.prize_weight = prize_weight;
}
}
}
- 第一步:新建一个奖品实体
奖品实体必须含有两个字段,一个用于区分的名称/ID;一个权重
- 第二步:权重的核心算法
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 (d1 <= randomNumber && randomNumber < d2) {
random = i;
break;
}
}
我用一个表格展示循环的一周期,其中demo为了好计算,4个样例凑了个整数10,概率分别为0.1-0.2-0.3-0.4,实际使用过程中分子分母是分开计算的,不需非得凑整数且允许单个样例权重为0但不能为负数。
次数 | d1 | d2 | 概率区间 |
1 | 0 | 1/10 | 0 --1/10 |
2 | 1/10 | 3/10 | 1/10--3/10 |
3 | 3/10 | 6/10 | 3/10--6/10 |
4 | 6/10 | 1 | 6/10--10/10 |
原理就是利用Math.random()每次获取的值0<= x<1的随机分布,从而根据各自的概率比值来实现权重。
double randomNumber;
randomNumber = Math.random();
原文链接:http://blog.csdn.net/huyuyang6688/article/details/50480687