java实现一个抽奖概率类

来源:互联网 发布:域名注册商排名 编辑:程序博客网 时间:2024/05/20 15:57

原文地址:http://blog.csdn.net/codefunjava/article/details/44408555


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

[java] view plain copy
 print?
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3. import java.util.Random;  
  4.   
  5. /** 
  6.  * 抽奖工具类,概率和可以不等于1 
  7.  * 概率为百分数去掉百分号的部分,如10%,则为10 
  8.  * 抽奖操作如下: 
  9.  * 1.输入抽奖概率集合,【抽奖概率集合为{10.0, 20.0, 30.0}】 
  10.  * 2.生成连续集合,       【生成的连续集合为{(0.0, 10.0],(10.0, 30.0],(30.0, 60.0]}】 
  11.  * 3.生成随机数,          【生成方法为 random.nextDouble() * maxElement】 
  12.  * 4.判断随机数在哪个区间内,返回该区间的index【生成了随机数12.001,则它属于(10.0, 30.0],返回 index = 1】 
  13.  *  
  14.  */  
  15. public class LotteryUtil {  
  16.       
  17.     /** 
  18.      * 定义一个连续集合 
  19.      * 集合中元素x满足:(minElement,maxElement] 
  20.      * 数学表达式为:minElement < x <= maxElement 
  21.      * 
  22.      */  
  23.     public class ContinuousList {  
  24.           
  25.         private double minElement;  
  26.         private double maxElement;  
  27.           
  28.         public ContinuousList(double minElement, double maxElement){  
  29.             if(minElement > maxElement){  
  30.                 throw new IllegalArgumentException("区间不合理,minElement不能大于maxElement!");  
  31.             }  
  32.             this.minElement = minElement;  
  33.             this.maxElement = maxElement;  
  34.         }  
  35.           
  36.         /** 
  37.          * 判断当前集合是否包含特定元素 
  38.          * @param element 
  39.          * @return 
  40.          */  
  41.         public boolean isContainKey(double element){  
  42.             boolean flag = false;  
  43.             if(element > minElement && element <= maxElement){  
  44.                 flag = true;  
  45.             }  
  46.             return flag;  
  47.         }  
  48.           
  49.     }  
  50.       
  51.     private List<ContinuousList> lotteryList;   //概率连续集合  
  52.     private double maxElement;                  //这里只需要最大值,最小值默认为0.0  
  53.   
  54.     /** 
  55.      * 构造抽奖集合 
  56.      * @param list 为奖品的概率 
  57.      */  
  58.     public LotteryUtil(List<Double> list){  
  59.         lotteryList = new ArrayList<ContinuousList>();  
  60.         if(list.size() == 0){  
  61.             throw new IllegalArgumentException("抽奖集合不能为空!");  
  62.         }  
  63.         double minElement = 0d;  
  64.         ContinuousList continuousList = null;  
  65.         for(Double d : list){  
  66.             minElement = maxElement;  
  67.             maxElement = maxElement + d;  
  68.             continuousList = new ContinuousList(minElement, maxElement);  
  69.             lotteryList.add(continuousList);  
  70.         }  
  71.     }  
  72.       
  73.     /** 
  74.      * 进行抽奖操作 
  75.      * 返回:奖品的概率list集合中的下标 
  76.      */  
  77.     public int randomColunmIndex(){  
  78.         int index = -1;  
  79.         Random r = new Random();  
  80.         double d = r.nextDouble() * maxElement;  //生成0-1间的随机数  
  81.         if(d == 0d){  
  82.             d = r.nextDouble() * maxElement;     //防止生成0.0  
  83.         }  
  84.         int size = lotteryList.size();  
  85.         for(int i = 0; i < size; i++){  
  86.             ContinuousList cl = lotteryList.get(i);  
  87.             if(cl.isContainKey(d)){  
  88.                 index = i;  
  89.                 break;  
  90.             }  
  91.         }  
  92.         if(index == -1){  
  93.             throw new IllegalArgumentException("概率集合设置不合理!");  
  94.         }  
  95.         return index;  
  96.           
  97.     }  
  98.       
  99.     public double getMaxElement() {  
  100.         return maxElement;  
  101.     }  
  102.   
  103.     public List<ContinuousList> getLotteryList() {  
  104.         return lotteryList;  
  105.     }  
  106.     public void setLotteryList(List<ContinuousList> lotteryList) {  
  107.         this.lotteryList = lotteryList;  
  108.     }  
  109.   
  110.       
  111. }  
该工具类的基本思想是,将抽奖概率分布到数轴上,如现有三个抽奖概率10、20、30,将三者依次添加到概率集合中,则构造的数轴为:0~10范围内表示概率10,10~30范围内表示概率为20,30~60范围内表示概率为30,数轴上的长度对应着相应的概率。由这种处理方式可知,概率总和并不需要等于1。该工具类的成功与否在于Random.nextDouble()能否等概率地生成0~1之间的任意一个数。

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

[java] view plain copy
 print?
  1. package com.lottery;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.List;  
  6. import java.util.Map;  
  7. import java.util.Map.Entry;  
  8.   
  9. class Result{  
  10.     private int index;  
  11.     private int sumTime;  
  12.     private int time;  
  13.     private double probability;  
  14.     private double realProbability;  
  15.       
  16.     public int getIndex() {  
  17.         return index;  
  18.     }  
  19.   
  20.     public void setIndex(int index) {  
  21.         this.index = index;  
  22.     }  
  23.   
  24.     public int getTime() {  
  25.         return time;  
  26.     }  
  27.   
  28.     public void setTime(int time) {  
  29.         this.time = time;  
  30.     }  
  31.   
  32.     public int getSumTime() {  
  33.         return sumTime;  
  34.     }  
  35.   
  36.     public void setSumTime(int sumTime) {  
  37.         this.sumTime = sumTime;  
  38.     }  
  39.   
  40.     public double getProbability() {  
  41.         return probability;  
  42.     }  
  43.   
  44.     public double getRealProbability() {  
  45.         return realProbability;  
  46.     }  
  47.   
  48.     public void setRealProbability(double realProbability) {  
  49.         this.realProbability = realProbability;  
  50.     }  
  51.   
  52.     public Result(){  
  53.           
  54.     }  
  55.       
  56.     public Result(int index, int sumTime, int time, double realProbability) {  
  57.         this.setIndex(index);  
  58.         this.setTime(time);  
  59.         this.setSumTime(sumTime);  
  60.         this.setRealProbability(realProbability);  
  61.           
  62.     }  
  63.   
  64.     public String toString(){  
  65.         return "索引值:" + index + ",抽奖总数:" + sumTime + ",抽中次数:" + time + ",概率:"   
  66.                + realProbability + ",实际概率:" + (double)time/sumTime;  
  67.     }  
  68. }  
  69.   
  70. public class TestLottery {  
  71.       
  72.     static final int TIME = 100000;  
  73.       
  74.     public static void iteratorMap(Map<Integer, Integer> map, List<Double> list){  
  75.         for(Entry<Integer, Integer> entry : map.entrySet()){  
  76.             int index = entry.getKey();  
  77.             int time  = entry.getValue();  
  78.             Result result = new Result(index, TIME, time, list.get(index));  
  79.             System.out.println(result);  
  80.         }  
  81.     }  
  82.       
  83.     public static void main(String[] args) {  
  84.         //构造概率集合  
  85.         List<Double> list = new ArrayList<Double>();  
  86.         list.add(20d);  
  87.         list.add(80d);  
  88.         list.add(50d);  
  89.         list.add(30d);  
  90.         LotteryUtil ll = new LotteryUtil(list);  
  91.         double sumProbability = ll.getMaxElement();  
  92.           
  93.         Map<Integer, Integer> map = new HashMap<Integer, Integer>();  
  94.         for(int i = 0; i < TIME; i++){  
  95.             int index = ll.randomColunmIndex();  
  96.             if(map.containsKey(index)){  
  97.                 map.put(index, map.get(index) + 1);  
  98.             }else{  
  99.                 map.put(index, 1);  
  100.             }  
  101.         }  
  102.         for(int i = 0; i < list.size(); i++){  
  103.             double probability = list.get(i) / sumProbability;  
  104.             list.set(i, probability);  
  105.         }  
  106.         iteratorMap(map, list);  
  107.           
  108.     }  
  109.       
  110.       
  111.       
  112. }  

运行结果:


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

以下说明此类调用方式:

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





0 0
原创粉丝点击