Java 队列随机工具类
队列随机工具类: 按顺序取一个少一个,取完一轮之后,再从头开始取;以达到尽量平均的效果
随机
某些场景下使用随机达到想要的效果并不理想,比如有时候想尽量每个值都平均一点
示例:0~10的随机数,获取1w次后,打印每个数的随机到的次数:
import java.util.HashMap;
import java.util.Map;
/**
* Created by xuyinglong on 14-12-23.
*/
public class Test {
/**
* 区间随机数 [min, max)
* @param min 最小值 包含
* @param max 最大值 不包含
*/
public static int rand(int min, int max) {
double r = Math.random();
return (int) Math.floor(r * (max - min)) + min;
}
public static void main(String[] args) {
Map<Integer, Integer> dict = new HashMap<Integer, Integer>();
for (int i = 0; i < 10000; i++) {
// 随机 [0,10)
int d = rand(0, 10);
// 次数+1
Integer cnt = dict.get(d);
dict.put(d, (cnt == null) ? 0 : ++cnt);
}
System.out.println( dict );
}
}
运行一次的结果:
{0=972, 1=974, 2=997, 3=1034, 4=985, 5=988, 6=983, 7=1009, 8=1038, 9=1010}
结果大致上还是是比较均匀的
尽量平均
但是这种方式随机实际做不到尽可能的平均
举个例子:6个人分一筐橘子,只能按个数分,这个时候丢骰子就不太好了,虽然每个人的概率是一样的,那么就一人拿一个,拿完为止。这样大不了只比比别人少一个而已。
import java.util.ArrayList;
import java.util.List;
/**
* 队列随机工具类:按顺序取一个少一个,取完一轮之后,再从头开始取
* Created by xuyinglong on 17/8/9.
*/
public class QueueRandomUtil<T> {
/** 数据是否存在 */
public static <T> boolean exists(String key) {
return CacheUtils.exists(key);
}
/** 设置缓存数据 */
public static <T> boolean set(String key, List<T> list, int minutes) {
return CacheUtils.set(key, list, minutes);
}
/** 随机获取几个数据 */
public synchronized static <T> List<T> rand(String key, int cnt) {
List<T> list = (List<T>) CacheUtils.get(key);
if (ParamUtil.isEmpty(list)) return null;
// 下标KEY
String subIndexKey = "QRU_" + key + "_SUBINDEX";
Integer subIndex = (Integer) CacheUtils.get(subIndexKey);
if (subIndex == null) subIndex = 0;
// 按下标其实值获取值
List<T> data = new ArrayList<T>();
for (int i = 0; i < cnt; i++) {
if (subIndex != 0 && subIndex >= list.size()) {
subIndex = 0;
}
data.add(list.get(subIndex));
subIndex++;
}
CacheUtils.set(subIndexKey, subIndex, 60); // 1h
return data;
}
public static void main(String[] args) throws InterruptedException {
// 数据准备
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
list.add(i + "");
}
System.out.println("原始数据:" + list);
String key = "hello";
// 如果数据过期, 需要重新设置数据....
if (!QueueRandomUtil.exists(key)) {
QueueRandomUtil.set(key, list, 5); // 数据重新加载
}
// 获取数据测试 10次
for (int i = 0; i < 10; i++) {
int cnt = RandomUtil.rand(0, 15);
List<String> r = QueueRandomUtil.rand(key, cnt);
Thread.sleep(1 * 1000); // 2s
System.out.println("index:" + i + "\tcnt:" + cnt + "\tdata:" + r);
}
}
}
这里利用的缓存机制,把数据列表和下标都存起来了,每次使用的时候按照最后的索引来取数据,如此循环取数据,达到尽量平均的效果!
测试结果:
原始数据:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
index:0 cnt:9 data:[0, 1, 2, 3, 4, 5, 6, 7, 8]
index:1 cnt:14 data:[9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2]
index:2 cnt:5 data:[3, 4, 5, 6, 7]
index:3 cnt:14 data:[8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]
index:4 cnt:7 data:[2, 3, 4, 5, 6, 7, 8]
index:5 cnt:5 data:[9, 0, 1, 2, 3]
index:6 cnt:11 data:[4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4]
index:7 cnt:1 data:[5]
index:8 cnt:11 data:[6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6]
index:9 cnt:13 data:[7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
CacheUtils
是一个内存缓存工具类 请参考:缓存管理工具类
参考:
blog comments powered by Disqus