java实现一个抽奖概率类

来源:互联网 发布:自动化办公软件下载 编辑:程序博客网 时间:2024/06/02 00:10

在一些项目需求中,可能会遇到抽奖问题,如提供一系列奖品及获奖概率,要求根据概率返回每次抽到的奖品。以下是本人在实际项目中写的一个抽奖工具类,与大家共同分享:

import java.util.ArrayList;import java.util.List;import java.util.Random;/** * 抽奖工具类,概率和可以不等于1 * 概率为百分数去掉百分号的部分,如10%,则为10 * 抽奖操作如下: * 1.输入抽奖概率集合,【抽奖概率集合为{10.0, 20.0, 30.0}】 * 2.生成连续集合,       【生成的连续集合为{(0.0, 10.0],(10.0, 30.0],(30.0, 60.0]}】 * 3.生成随机数,          【生成方法为 random.nextDouble() * maxElement】 * 4.判断随机数在哪个区间内,返回该区间的index【生成了随机数12.001,则它属于(10.0, 30.0],返回 index = 1】 *  */public class LotteryUtil {/** * 定义一个连续集合 * 集合中元素x满足:(minElement,maxElement] * 数学表达式为:minElement < x <= maxElement * */public class ContinuousList {private double minElement;private double maxElement;public ContinuousList(double minElement, double maxElement){if(minElement > maxElement){throw new IllegalArgumentException("区间不合理,minElement不能大于maxElement!");}this.minElement = minElement;this.maxElement = maxElement;}/** * 判断当前集合是否包含特定元素 * @param element * @return */public boolean isContainKey(double element){boolean flag = false;if(element > minElement && element <= maxElement){flag = true;}return flag;}}private List<ContinuousList> lotteryList;   //概率连续集合private double maxElement; //这里只需要最大值,最小值默认为0.0/** * 构造抽奖集合 * @param list 为奖品的概率 */public LotteryUtil(List<Double> list){lotteryList = new ArrayList<ContinuousList>();if(list.size() == 0){throw new IllegalArgumentException("抽奖集合不能为空!");}double minElement = 0d;ContinuousList continuousList = null;for(Double d : list){minElement = maxElement;maxElement = maxElement + d;continuousList = new ContinuousList(minElement, maxElement);lotteryList.add(continuousList);}}/** * 进行抽奖操作 * 返回:奖品的概率list集合中的下标 */public int randomColunmIndex(){int index = -1;Random r = new Random();double d = r.nextDouble() * maxElement;  //生成0-1间的随机数if(d == 0d){d = r.nextDouble() * maxElement;     //防止生成0.0}int size = lotteryList.size();for(int i = 0; i < size; i++){ContinuousList cl = lotteryList.get(i);if(cl.isContainKey(d)){index = i;break;}}if(index == -1){throw new IllegalArgumentException("概率集合设置不合理!");}return index;}public double getMaxElement() {return maxElement;}public List<ContinuousList> getLotteryList() {return lotteryList;}public void setLotteryList(List<ContinuousList> lotteryList) {this.lotteryList = lotteryList;}}
该工具类的基本思想是,将抽奖概率分布到数轴上,如现有三个抽奖概率10、20、30,将三者依次添加到概率集合中,则构造的数轴为:0~10范围内表示概率10,10~30范围内表示概率为20,30~60范围内表示概率为30,数轴上的长度对应着相应的概率。由这种处理方式可知,概率总和并不需要等于1。该工具类的成功与否在于Random.nextDouble()能否等概率地生成0~1之间的任意一个数。

对该抽奖工具进行测试,测试类如下:

package com.lottery;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;class Result{private int index;private int sumTime;private int time;private double probability;private double realProbability;public int getIndex() {return index;}public void setIndex(int index) {this.index = index;}public int getTime() {return time;}public void setTime(int time) {this.time = time;}public int getSumTime() {return sumTime;}public void setSumTime(int sumTime) {this.sumTime = sumTime;}public double getProbability() {return probability;}public double getRealProbability() {return realProbability;}public void setRealProbability(double realProbability) {this.realProbability = realProbability;}public Result(){}public Result(int index, int sumTime, int time, double realProbability) {this.setIndex(index);this.setTime(time);this.setSumTime(sumTime);this.setRealProbability(realProbability);}public String toString(){return "索引值:" + index + ",抽奖总数:" + sumTime + ",抽中次数:" + time + ",概率:"            + realProbability + ",实际概率:" + (double)time/sumTime;}}public class TestLottery {static final int TIME = 100000;public static void iteratorMap(Map<Integer, Integer> map, List<Double> list){for(Entry<Integer, Integer> entry : map.entrySet()){int index = entry.getKey();int time  = entry.getValue();Result result = new Result(index, TIME, time, list.get(index));System.out.println(result);}}public static void main(String[] args) {//构造概率集合List<Double> list = new ArrayList<Double>();list.add(20d);list.add(80d);list.add(50d);list.add(30d);LotteryUtil ll = new LotteryUtil(list);double sumProbability = ll.getMaxElement();Map<Integer, Integer> map = new HashMap<Integer, Integer>();for(int i = 0; i < TIME; i++){int index = ll.randomColunmIndex();if(map.containsKey(index)){map.put(index, map.get(index) + 1);}else{map.put(index, 1);}}for(int i = 0; i < list.size(); i++){double probability = list.get(i) / sumProbability;list.set(i, probability);}iteratorMap(map, list);}}

运行结果:


由结果可知,抽奖100000时, 得到的实际概率基本与正式概率相当。

以下说明此类调用方式:

public LotteryUtil(List<Double> list)说明:构造方法,传入参数为一个概率集合
public int randomColunmIndex()功能:进行抽奖操作,返回List集合的索引下标,此下标对应的概率的奖品即为抽中的奖品




0 0