[JAVA] - 高效的从 m 个元素中随机选中 n 个

Posted hcl00

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[JAVA] - 高效的从 m 个元素中随机选中 n 个相关的知识,希望对你有一定的参考价值。

之前业务中曾经遇到过从m个元素中选取 n 个的需求,当时只是跑循环根据长度进行随机选取,然后放入 Set 中去重,一直到收集到足够的个数。

这样做的缺点很明显,当剩下的元素个数越少的时候,选取的元素越容易重复,并且,使用 Set 去重,值相同的字符串会被认为是相同的元素,即使给入的数组确实有重复的数据。

直到最近看到了 Fisher-Yates 洗牌算法,从中收到启发,写了一个从 m 个元素中选取 n 个的方法,该方法性能上有了很大提升,并且可以保证取到的元素的索引绝对不会重复。如果数组中的确有相同的元素,也不会影响到被选取的概率。

 1     public static <T> T[] randomSelected(T[] array, int num) {
 2         T[] temp = Arrays.copyOf(array, array.length);   // 获得一个该数组的复制
 3         int length = temp.length;
 4         int left = length;
 5         while (length - left < num) {  // length - left 为还需要计算多少次
 6             int i = (int) Math.floor(Math.random() * left--);  // 随机选取一个元素,left 自减,这样不会覆盖上次产生的结果,并将下次选取的范围缩小
 7             T tmp = temp[i];  // 将被选中的数与数组的最后一位进行调换
 8             temp[i] = temp[left];
 9             temp[left] = tmp;
10         }
11         return Arrays.copyOfRange(temp, 0, num > length ? length : num);  // 从临时数组中复制出指定长度的数组
12     }

该算法不仅速度快,而且索引绝对不会重复!(如果数组里面有重复的元素,我认为这是你想要的结果,毕竟去重不是一件难事)

如果 传入的 num 等于数组的长度,还可以得到一个被打乱了顺序的数组!

 

以上是关于[JAVA] - 高效的从 m 个元素中随机选中 n 个的主要内容,如果未能解决你的问题,请参考以下文章

[CSP-S模拟测试]:Set(随机化)

从N个元素的集合中随机取m个元素的算法实现

m元素集合的n个元素子集

java程序,随机产生包含20个元素的数组,求出数组中的最大值,最小值和平均值

MATLAB如何把n个数不重复地随机分为m组

用java编程序 对一个由5个整数组成的数组,按照其内元素的从大到小排序