Android Studio 如何实现指定范围内逐个生成不重复随机数
逐次生成不重复区间随机数的Android实现方案
核心实现思路
采用惰性版本的Fisher-Yates洗牌算法实现,完全满足逐次调用、不重复、全量覆盖指定区间的需求,规避传统“生成随机数+去重校验”方案的后期性能崩塌问题。整个实现不需要预先生成全量打乱的数字序列,所有随机交换动作都在方法被调用时按需完成,每次调用的时间复杂度稳定为O(1)。
具体实现逻辑
- 初始化阶段:
- 记录指定随机区间的上下限
min、max,计算区间内总元素个数totalCount = max - min + 1 - 维护剩余可抽取元素的游标
remainingIndex,初始值为totalCount - 1 - 初始化数值池数组:位置
i存储的数值为min + i,无需提前做全量打乱,无额外初始化计算开销
- 记录指定随机区间的上下限
- 单次调用
generateAnyRandom()的执行流程:- 先做边界校验:如果
remainingIndex < 0,代表区间内所有数字已经全部生成完毕,可根据业务规则抛出异常或返回约定错误值 - 在
[0, remainingIndex]的闭区间内生成一个随机整数randomPos作为本次抽取的位置 - 取出数值池中
randomPos位置的数值,作为本次要返回的随机结果 - 将数值池中
randomPos位置的元素,和remainingIndex位置的元素做交换——把已经被抽走的元素移到数组末尾的“已使用区”,后续的随机抽取范围永远不会覆盖这个区域 - 将
remainingIndex向前移动1位,等待下一次方法调用
- 先做边界校验:如果
常见实现误区
- 误区1:用HashSet存储已经返回过的数字,每次生成随机数后校验是否存在于集合中。这种方案在剩余可选数字越少时,随机生成的碰撞概率越高:比如最后只剩2个可选数时,平均需要生成4次随机数才能命中未重复的值;只剩1个可选数时,理论上需要上千次随机生成才能命中,性能完全不可控。
- 误区2:一次性生成全量打乱的数字列表存在内存中,每次调用弹出一个值。这种方案虽然性能达标,但如果区间范围过大(比如1到100万),一次性打乱并生成全量列表会占用不必要的计算和内存资源,而惰性洗牌方案在初始化时仅生成连续的有序数组,没有提前打乱的额外开销,所有随机动作按需触发,内存占用和前者一致,但实现逻辑更轻量化。
参考代码实现
import java.util.Random; public class UniqueRandomGenerator { private final int min; private final int max; private int remainingIndex; private int[] numberPool; private final Random random = new Random(); /** * 初始化生成器 * @param min 随机区间下限 * @param max 随机区间上限 */ public UniqueRandomGenerator(int min, int max) { this.min = min; this.max = max; int totalCount = max - min + 1; this.remainingIndex = totalCount - 1; this.numberPool = new int[totalCount]; // 初始化数值池,无提前打乱开销 for (int i = 0; i < totalCount; i++) { numberPool[i] = min + i; } } /** * 对外暴露的随机数生成方法 * @return 区间内未返回过的随机数 */ public int generateAnyRandom() { if (remainingIndex < 0) { throw new IllegalStateException("指定区间内的所有数值已全部生成完毕"); } // 在剩余可抽取范围内生成随机位置 int randomPos = random.nextInt(remainingIndex + 1); int result = numberPool[randomPos]; // 交换抽取位置和剩余范围末尾位置 int temp = numberPool[randomPos]; numberPool[randomPos] = numberPool[remainingIndex]; numberPool[remainingIndex] = temp; // 剩余游标前移 remainingIndex--; return result; } }
内容的提问来源于stack exchange,提问作者Bhaskar Jyoti Dutta
相关产品推荐
相关产品推荐

