Java - 加权随机算法--Demo
Java LoadBalanceUtil 负载均衡、轮询加权 https://www.cnblogs.com/vipsoft/p/19728820
Java - 加权随机算法 - 示例:https://www.cnblogs.com/vipsoft/p/19742349
A 权重 1 、B 权重 2 、C 权重 3
怎么能每次根据权重,做随机得到 A\B\C
我给你提供几种Java实现权重随机算法的方法:
方法一:数组扩展法(最简单)
import java.util.Random;
public class WeightRandom {
private static final Random random = new Random();
public static String getRandomByWeight() {
// 权重:A(1), B(2), C(3)
String[] items = {"A", "B", "C"};
int[] weights = {1, 2, 3};
// 计算总权重
int totalWeight = 0;
for (int weight : weights) {
totalWeight += weight;
}
// 生成随机数
int randomNum = random.nextInt(totalWeight); // 0-5
// 根据权重选择
if (randomNum < 1) {
return "A";
} else if (randomNum < 1 + 2) {
return "B";
} else {
return "C";
}
}
public static void main(String[] args) {
// 测试100次,查看分布
int aCount = 0, bCount = 0, cCount = 0;
for (int i = 0; i < 100; i++) {
String result = getRandomByWeight();
switch (result) {
case "A": aCount++; break;
case "B": bCount++; break;
case "C": cCount++; break;
}
}
System.out.printf("A: %d次, B: %d次, C: %d次%n", aCount, bCount, cCount);
}
}
方法二:通用工具类(推荐)
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class WeightRandomUtil<T> {
private final List<WeightItem<T>> items = new ArrayList<>();
private int totalWeight = 0;
private final Random random = ThreadLocalRandom.current();
public static class WeightItem<T> {
T item;
int weight;
public WeightItem(T item, int weight) {
this.item = item;
this.weight = weight;
}
}
public void addItem(T item, int weight) {
items.add(new WeightItem<>(item, weight));
totalWeight += weight;
}
public T next() {
if (items.isEmpty() || totalWeight == 0) {
return null;
}
int randomNum = random.nextInt(totalWeight);
int currentWeight = 0;
for (WeightItem<T> item : items) {
currentWeight += item.weight;
if (randomNum < currentWeight) {
return item.item;
}
}
return null; // 不应该到这里
}
public static void main(String[] args) {
WeightRandomUtil<String> wr = new WeightRandomUtil<>();
wr.addItem("A", 1);
wr.addItem("B", 2);
wr.addItem("C", 3);
// 测试
Map<String, Integer> countMap = new HashMap<>();
for (int i = 0; i < 1000; i++) {
String result = wr.next();
countMap.merge(result, 1, Integer::sum);
}
System.out.println("测试结果:");
countMap.forEach((k, v) ->
System.out.printf("%s: %d次 (占比 %.1f%%)%n",
k, v, v / 10.0));
}
}
方法三:TreeMap实现(二分查找优化)
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class WeightRandomTreeMap<T> {
private final TreeMap<Integer, T> weightMap = new TreeMap<>();
private int totalWeight = 0;
private final Random random = ThreadLocalRandom.current();
public void addItem(T item, int weight) {
totalWeight += weight;
weightMap.put(totalWeight, item);
}
public T next() {
if (weightMap.isEmpty()) {
return null;
}
int randomNum = random.nextInt(totalWeight) + 1;
Map.Entry<Integer, T> entry = weightMap.ceilingEntry(randomNum);
return entry != null ? entry.getValue() : null;
}
public static void main(String[] args) {
WeightRandomTreeMap<String> wr = new WeightRandomTreeMap<>();
wr.addItem("A", 1);
wr.addItem("B", 2);
wr.addItem("C", 3);
// 测试
Map<String, Integer> countMap = new HashMap<>();
for (int i = 0; i < 1000; i++) {
String result = wr.next();
countMap.merge(result, 1, Integer::sum);
}
System.out.println("测试结果:");
countMap.forEach((k, v) ->
System.out.printf("%s: %d次 (占比 %.1f%%)%n",
k, v, v / 10.0));
}
}
方法四:Apache Commons Math(第三方库)
如果项目中使用Apache Commons Math,可以更简洁:
import org.apache.commons.math3.distribution.EnumeratedDistribution;
import org.apache.commons.math3.util.Pair;
import java.util.ArrayList;
import java.util.List;
public class WeightRandomApache {
public static void main(String[] args) {
List<Pair<String, Double>> items = new ArrayList<>();
items.add(new Pair<>("A", 1.0));
items.add(new Pair<>("B", 2.0));
items.add(new Pair<>("C", 3.0));
EnumeratedDistribution<String> distribution =
new EnumeratedDistribution<>(items);
// 测试
for (int i = 0; i < 10; i++) {
System.out.print(distribution.sample() + " ");
}
}
}
建议
- 简单场景:使用方法一,最直观
- 通用需求:使用方法二,可重用性好
- 大数据量:使用方法三(TreeMap),查找效率高(O(log n))
- 已有Apache Commons:使用方法四,代码最简洁
你的权重配置(A:1, B:2, C:3)意味着:
- A的概率:1/6 ≈ 16.7%
- B的概率:2/6 ≈ 33.3%
- C的概率:3/6 = 50%
本文来自博客园,作者:VipSoft 转载请注明原文链接:https://www.cnblogs.com/vipsoft/p/19741845
浙公网安备 33010602011771号