作者zanyking (遥远的旅人)
看板java
标题[讨论] 一个作弊用的骰子(最终版)
时间Mon Apr 10 13:46:33 2006
上次那个问题的物件导向版。
支援大数(long)运算。
实做执行期修改权值。updateWeight()方法。
有兴趣的大大们玩玩吧。
____________________________<<程式码>>____________________________________
package dice;
import java.util.Random;
import java.util.TreeMap;
/**
*
* @author IANTSAI <br>
* 系统:int 32 bits, long 64 bits <br>
* 多绪:这不是一个thread safe的物件,请小心。<br>
* 用途:一个可以作弊的骰子。<br>
* 修改.移植:可以的话,把weightArr、AWArr也换成不定型态,在其他语言,例如C++
、C#中可以考虑<br>
* 修改.移植.实做:weight、AccumulateWeight必须实做 operator(+,+=,-,-=,>,<)
* 修改.移植.建议:weight extends int ,AccumulateWeight extends long
* @param <T>
*/
public class WeightRandom<T>
{
/**
*
* @param args
*/
public static void main(String[] args)
{
String[] valueArr = new String[]{"1点","2点","3点","4点","5点","6点"};
int[] weightArr = new int[]{100,100,100,100,100,10000};
WeightRandom<String> cheatDice = new WeightRandom<String>();
cheatDice.init(valueArr,weightArr);
doTest(cheatDice);
cheatDice.updateWeight(5,100);
doTest(cheatDice);
}
public static void doTest(WeightRandom<String> cheatDice)
{
int loop = 1000000;
TreeMap<String,Integer> map = new TreeMap<String,Integer>();
long start = System.currentTimeMillis();
for(int i=0;i<loop;i++)
{
String diceValue = cheatDice.randValue();
if(map.containsKey(diceValue))
map.put(diceValue,map.get(diceValue)+1);
else map.put(diceValue,1);
}
long end = System.currentTimeMillis();
for(String ent : map.keySet())
System.out.println(ent+" : "+map.get(ent)+" 次");
System.out.println();
System.out.println("总共骰了 "+loop+" 次");
System.out.println("花费时间: "+(float)(end-start)/1000+" 秒.");
}
private T[] valueArr;
private int[] weightArr;
private long[] AWArr;
/**
* 初始化 值阵(valueArr) 与 权阵(weightArr)
* @param _valueArr 值阵 不可为null, 必须与weightArr等长
* @param _weightArr 权阵 不可为null, 必须与valueArr等长, 元素不可为负数 ,
* 所有元素的总和不可 == 0
*/
public void init(T[]_valueArr,int[]_weightArr)
{
if(_valueArr==null||_weightArr==null||
_valueArr.length!=_weightArr.length)
throw new IllegalArgumentException("different arg length!!!");
this.valueArr = _valueArr;
this.weightArr = _weightArr;
this.AWArr = createAccumulateWeightArray(_weightArr);
}
/**
* 更新累进权阵
* @return
*/
public long[] createAccumulateWeightArray(int[] _weightArr)
{
int size = _weightArr.length;
long[] _AWArr = new long[size];
long temp=0;
for(int i=0;i<size;i++)
{
if(_weightArr[i] < 0)
throw new IllegalArgumentException("Weight can not < 0!!!");
temp+=_weightArr[i];
_AWArr[i]=temp;
}
if(temp == 0)
throw new IllegalArgumentException("weight Sigma is ZERO!!!");
return _AWArr;
}
/**
* 执行期更新权重矩阵参数,连带更新AWArr
* @param index
* @param value
*/
public void updateWeight(int index, int value)
{
if(index < weightArr.length)
{
int def = value - this.weightArr[index];
this.weightArr[index] = value;
for(int i=index,j=AWArr.length;i<j;i++)
AWArr[i] += def;
}
else throw new IndexOutOfBoundsException("index="+index);
}
/**
* 依据权重,乱数回传一个valueArr里的元素。
* @return
*/
public T randValue()
{
//java api 里没找到(我懒),所以自己做
long dice = RandUtil.nextLong(AWArr[AWArr.length-1])+1;
//自己作来玩的。
int index =
LeftAreaFinder.bineryLeftAreaSearch( dice,this.AWArr);
return valueArr[index];
}
}//end of class
/**
*
* @author IANTSAI
*判断是否落在左区域范围(右极限)内,如果Key大於最後一个右极限,回传
-arr.length
*/
class LeftAreaFinder
{
private LeftAreaFinder(){}
/**
* 使用BinarySearch寻找是否落在左区域范围(右极限)内<br>
* ,如果Key大於最後一个右极限,回传 -arr.length
* @param key
* @return
*/
public static int bineryLeftAreaSearch(long key,long[]arr)
{
int low_of = 0;
int up_of = arr.length-1;
if(key>arr[up_of])return -arr.length;
while (low_of <= up_of)
{
int middle = (low_of + up_of) >> 1;
long midLeft = arr[middle];
if(key < midLeft) up_of = middle-1;
else if(key > midLeft)low_of = middle+1;
else return middle;
}
return low_of;
}
/**
* 使用sequenceSearch判断是否落在左区域范围(右极限)内,<br>
* 如果Key大於最後一个右极限,回传 -arr.length
* @param key
* @return
*/
public static int sequenceLeftAreaSearch(long key,long[]arr)
{
for(int i=0,j=arr.length;i<j;i++)if(key < arr[i])return i;
return -arr.length;
}
}//end of class
/**
* 实做长整数的nexLong方法
* @author IANTSAI
*
*/
class RandUtil
{
private static final int INT32_MAX = 1 << 30;//int 的32位元系统极值
private RandUtil(){}
/**
* 乱数产生一个在(0~max-1)之间的long 值。
* @param max
* @return
*/
public static long nextLong(long max)
{
Random rand = new Random();
long randValue;
if(max < INT32_MAX)randValue = rand.nextInt((int)max);
else randValue = Math.abs(rand.nextLong()) % max;
return randValue;
}
}
________________________________<<程式码结束>>_______________________________
--
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 60.248.27.110
※ 编辑: zanyking 来自: 60.248.27.110 (04/10 13:46)