文章目录
场景
按照权重给用户分组;比如按照权重20,30,40,10给用户分组为A,B,C,D
实现
内部实现也是基于TreeMap.tailMap的方法,
详见https://blog.51cto.com/javayida/7485758#TreeMaptailMap_4
参考hutool的类:cn.hutool.core.lang.WeightRandom
权重随机算法实现
平时,经常会遇到权重随机算法,从不同权重的N个元素中随机选择一个,并使得总体选择结果是按照权重分布的。如广告投放、负载均衡等。
如有4个元素A、B、C、D,权重分别为1、2、3、4,随机结果中A:B:C:D的比例要为1:2:3:4。
总体思路:累加每个元素的权重A(1)-B(3)-C(6)-D(10),则4个元素的的权重管辖区间分别为[0,1)、[1,3)、[3,6)、[6,10)。 然后随机出一个[0,10)之间的随机数。落在哪个区间,则该区间之后的元素即为按权重命中的元素。
测试main方法
java
import cn.hutool.core.lang.WeightRandom;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName RandomTest
* @Author yida
* @Date 2023-09-14 18:26
* @Description RandomTest
*/
public class RandomTest {
public static void main(String[] args) {
test();
}
public static void test() {
List<WeightRandom.WeightObj<String>> weightList = new ArrayList<>();
weightList.add(new WeightRandom.WeightObj<>("A", 20));
weightList.add(new WeightRandom.WeightObj<>("B", 30));
weightList.add(new WeightRandom.WeightObj<>("C", 40));
weightList.add(new WeightRandom.WeightObj<>("D", 10));
WeightRandom<String> wr = RandomUtil.weightRandom(weightList);
String str = "";
int num_a = 0, num_b = 0, num_c = 0, num_d = 0;
int testCount = 10000;
for (int i = 0; i < testCount; i++) {
str = wr.next();
switch (str) {
case "A":
num_a = num_a + 1;
break;
case "B":
num_b = num_b + 1;
break;
case "C":
num_c = num_c + 1;
break;
case "D":
num_d = num_d + 1;
break;
}
}
System.out.println("A-" + num_a + "-------" + NumberUtil.div(num_a, testCount, 2) * 100+"%");
System.out.println("B-" + num_b + "-------" + NumberUtil.div(num_b, testCount, 2) * 100+"%");
System.out.println("C-" + num_c + "-------" + NumberUtil.div(num_c, testCount, 2) * 100+"%");
System.out.println("D-" + num_d + "-------" + NumberUtil.div(num_d, testCount, 2) * 100+"%");
}
}
执行结果
java
A-1958-------20.0%
B-3094-------31.0%
C-3972-------40.0%
D-976-------10.0%
代码详解WeightRandom的next方法
treeMap.tailMap是Java中的一个方法,用于返回一个新的map,其中包含了原map中所有大于等于指定键的键值对。
在Java中,Map是一种将键映射到值的数据结构。其中,TreeMap是一种基于红黑树实现的有序映射。它可以按照键的自然顺序或者指定的比较器顺序对键进行排序。
tailMap方法是TreeMap类中的一个方法,用于返回一个新的TreeMap,其中包含了原TreeMap中所有大于等于指定键的键值对。这个方法的定义如下:
public SortedMap<K,V> tailMap(K fromKey)
java
/**
* 下一个随机对象
*
* @return 随机对象
*/
public T next() {
if(MapUtil.isEmpty(this.weightMap)) {
return null;
}
final Random random = RandomUtil.getRandom();
final double randomWeight = this.weightMap.lastKey() * random.nextDouble();
final SortedMap<Double, T> tailMap = this.weightMap.tailMap(randomWeight, false);
return this.weightMap.get(tailMap.firstKey());
}