原文地址:http://blog.csdn.net/codefunjava/article/details/44408555
在一些项目需求中,可能会遇到抽奖问题,如提供一系列奖品及获奖概率,要求根据概率返回每次抽到的奖品。以下是本人在实际项目中写的一个抽奖工具类,与大家共同分享:
- 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;
- }
- }
对该抽奖工具进行测试,测试类如下:
- 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集合的索引下标,此下标对应的概率的奖品即为抽中的奖品