Java带权重随机采样采用前缀和+二分查找:先构建权重前缀和数组,再生成[0,总权重)随机数并二分定位区间,高效省内存,适用于装备掉落等场景。

在 Java 中实现带权重的随机采样,核心思路是将概率映射为“权重区间”,再通过生成一个总权重范围内的随机数,查找其落入哪个区间——这本质上是前缀和 + 二分查找的经典应用。它比重复添加元素到列表(如把 70% 的权重展开成 70 个相同项)更省内存、更高效,尤其适合装备掉落这类权重固定但种类较多的场景。
1. 准备权重与物品映射关系
先定义装备等级及其对应权重(可为整数或浮点数)。推荐用整数避免浮点误差,比如:普通(50)、稀有(30)、史诗(15)、传说(5)。注意权重不要求归一化,总和也不必为 100。
用两个平行数组或一个对象数组保存数据:
String[] items = {"普通", "稀有", "史诗", "传说"};
int[] weights = {50, 30, 15, 5};
2. 构建前缀和数组
前缀和数组 prefixSum[i] 表示前 i+1 个权重的累计和。它让每个物品对应一段连续整数区间:
- 普通:[0, 49] → 长度 50
- 稀有:[50, 79] → 长度 30
- 史诗:[80, 94] → 长度 15
- 传说:[95, 99] → 长度 5
代码实现:
int[] prefixSum = new int[weights.length]; prefixSum[0] = weights[0]; for (int i = 1; i
3. 生成随机数并二分定位
生成 [0, totalWeight) 范围内的随机整数(totalWeight = prefixSum[prefixSum.length - 1]),然后在 prefixSum 中找第一个 ≥ 该随机数的位置——这就是命中物品的下标。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
Java 提供 Arrays.binarySearch,但需注意其返回值逻辑:找到则返回索引,未找到返回 -(insertionPoint) - 1。更清晰的做法是手写二分或使用 TreeSet.floorEntry(若改用 TreeMap 存储累积边界)。
简洁安全的手写二分示例:
Random rand = new Random(); int total = prefixSum[prefixSum.length - 1]; int r = rand.nextInt(total); // [0, total) <p>// 二分查找第一个 >= r 的 prefixSum 索引 int left = 0, right = prefixSum.length; while (left </p>
4. 封装为可复用工具方法
把上述逻辑封装成泛型方法,支持任意类型物品和整数权重:
public static <t> T weightedRandom(T[] items, int[] weights, Random rand) {
if (items.length == 0 || weights.length != items.length)
throw new IllegalArgumentException();
<pre class="brush:java;toolbar:false;">int[] prefix = new int[weights.length];
prefix[0] = weights[0];
for (int i = 1; i <p>}</p><p>// 使用示例:
String result = weightedRandom(items, weights, new Random());</p>不复杂但容易忽略:权重全为 0 时需额外校验;若需线程安全,建议复用同一个 Random 实例(如 ThreadLocalRandom.current());实际项目中可进一步封装为 Builder 模式支持动态权重更新。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










