1. 程式人生 > >java實現一個抽獎概率類

java實現一個抽獎概率類

在一些專案需求中,可能會遇到抽獎問題,如提供一系列獎品及獲獎概率,要求根據概率返回每次抽到的獎品。以下是本人在實際專案中寫的一個抽獎工具類,與大家共同分享:

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集合的索引下標,此下標對應的概率的獎品即為抽中的獎品



相關推薦

java實現一個抽獎概率

在一些專案需求中,可能會遇到抽獎問題,如提供一系列獎品及獲獎概率,要求根據概率返回每次抽到的獎品。以下是本人在實際專案中寫的一個抽獎工具類,與大家共同分享: import java.util.ArrayList; import java.util.List; import

java實現一個簡單的單用戶登陸功能的思路

get 單用戶 這樣的 簡單的 lock ref 數據庫 清除 一個 引用 所謂“單用戶單賬戶登錄”是指:在同一系統中,一個用戶名不能在兩個地方同時登錄。 我們參照 QQ 實現效果:當某賬號在 A 處登錄後,在未退出的情況下,如果再到 B 處登錄,那麽,系統會擠下 A 處

python實現一個層次聚方法

mac ima 優先隊列 () don 標簽 中位數 filepath normal 層次聚類(Hierarchical Clustering) 一.概念   層次聚類不需要指定聚類的數目,首先它是將數據中的每個實例看作一個類,然後將最相似的兩個類合並,該過程叠代計算只到剩

java實現一個簡易編譯器1-詞法解析入門

new 概念 自加 我們 sta 數字 獲得 () 操作系統 本文對應代碼下載地址為: http://download.csdn.net/detail/tyler_download/9435103 視頻地址: http://v.youku.com/v_show/id_XMT

java算法面試題:排序都有哪幾種方法?請列舉。用JAVA實現一個快速排序。選擇冒泡快速集合至少4種方法排序

算法 err div println rda print 算法面試 ++ 快速排序 package com.swift; import java.util.ArrayList; import java.util.Collections; import java.util

Java實現一個簡單的事件監聽器

tro 模型 when rgs sdf span 傳遞 inter pre 關於事件監聽我們需要知道的一些基礎知識。 a)事件三要素: source -- 事件源 when -- 事件發生時間 message -- 事件主題消息

java實現一個最簡單的tomcat服務

連接數 accep print tex soc ins udp web服務 reply 1.如何啟動? main方法是程序的入口,tomcat也不例外,查看tomcat源碼,發現main是在Bootstrap 類中的; 2.如何建立連接? 要通訊,必須要建議so

javascript實現控制抽獎概率

parse lse ava () nbsp span cti man fun var manay; var a=0; //隨機數留倆位小數 function random(min,max){   return (Math.random()*(max-min) + min)

java實現一個簡單的計數器

random imp num count 簡單的 [] dom .com bnu package com.fengunion.sf;import org.junit.platform.commons.util.StringUtils;import java.util.Has

JavaJava實現一個“計算文字中某個詞出現頻率”的應用程式

一、目的     計算某個詞出現頻率,可以很好的對一篇文章水平的評價提供客觀依據,比如在技術類文章中出現“的”字的頻率太高,說明此文章邏輯不夠嚴謹,本次應用程式的目的就是計算出指定文字中指定詞出現的頻率。   二、程式演示 有如下一個文字檔案w.txt,我們計算“的”字出

JavaJava實現一個簡單的“檢視檔案的二進位制碼瀏覽器”

一、檢視檔案的二進位制碼     想檢視一個檔案的二進位制碼有很多工具可以用HEX的方式讀檔案,例如:Notepad++、UltraEdit、HexViewer等等。 Notepad++的HEX-Editor:   二、DIY瀏覽器 1.初步實現的瀏覽功能: 軟體採用命

java實現一個簡單的驗證碼生成器

  最近看了網上很多大佬們寫的驗證碼生成,尋思著自己也寫一個,話不多說,程式碼如下:                                &

使用Java實現K-Means聚演算法

第一次寫部落格,隨便寫寫。 關於K-Means介紹很多,還不清楚可以查一些相關資料。 個人對其實現步驟簡單總結為4步: 1.選出k值,隨機出k個起始質心點。  2.分別計算每個點和k個起始質點之間的距離,就近歸類。  3.最終中心點集可以劃分為k類,

Java實現一個簡單的棧結構---Strack

棧是資料結構的一種,其限制是僅允許在表的一端進行插入和刪除運算。這一端被稱為棧頂,相對地,把另一端稱為棧底。 之前我覺得棧是一個非常難於理解的資料結構,其實不然,很多的時候真的是自己對於定義不清不楚,遇到想不通的問題便放棄了,對於實現一個簡單的棧結構,我們首先要明白採用什麼順序表結構作為底層

Java實現地區選擇工具

1.需要的jar包 <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version

java實現元組Tuple

package core; public class Tuple<K,V> { private K key; private V value; public Tuple(K key, V value) { this.key = key; this.value = v

java實現一個行鎖(RowLock)

java 版本的資料庫行鎖,使用wait/notify實現,當然可以使用別的方式如Lock下的await/signal 需求使用java寫一個類,這個類有一個lock(String identifie

用CSS實現一個抽獎轉盤

效果 基本是用CSS實現的,沒有用圖片,加一丟丟JS。完全沒有考慮相容性。 首先畫一個轉盤, <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <ti

Java實現一個簡單的郵箱格式判斷

郵箱要求: “@”不能在第一位 “”不能在最後一位 ,“@”和“”中間應該有字元 ,*** @ ***。***(標準格式) 當然還有更嚴格的校驗規則,我們此處考慮到這即可 具體的程式碼實現: package com.poin

Java實現一個簡單的兩人五子棋遊戲(六) 行棋方變換

1)選擇棋子 ✔️ 2)畫棋子 ✔️ 3)判斷勝負 ✔️ 4)交換行棋方 目標 前面我們已經畫好棋盤和棋子,並可以自由落子,且可以判斷棋盤中是否有五連珠。接下來的工作是,每次落子後交換行棋方(即將下一棋子顏色由白->黑或黑->白),並