【问题标题】:How to do a random-and-unique generator?如何做一个随机且唯一的生成器?
【发布时间】:2011-02-18 05:51:10
【问题描述】:

我已经写了一个随机生成器,它接受参数 a 和 b,其中 a 是最小值,b 是最大值,就像这个 randomGenerator(int a, int b)

接下来我要做的是:使用循环,然后生成从 a 到 b 的唯一编号。示例:

I want to have 8 unique numbers,
int a = 1;
int b = 10;
int value;

如果我进行循环,那么相同的数字会出现多次。知道怎么做吗?

我自己的方式是:

while(int i <= 8){
  randomGenerator(a,b);
  // if value is not in array, then insert into array
}

我被困在评论部分。有没有办法检查数组中是否存在变量?

编辑,根据nailxx的回答,我的理解是:

  • 从 a 到 b 的列表(如果按照我的例子,1 - 10)

  • “随机播放”它

  • 取前 8 项。是这个意思吗?

在 java 世界中,是否有“洗牌”功能或者我需要自己创建?

【问题讨论】:

  • 随机和独特几乎是相互排斥的术语。您只想创建一个“随机”数字列表,然后随机播放列表并从列表中弹出。

标签: java arrays random


【解决方案1】:

获取从ab 顺序分布的元素的列表,将其打乱并在每个请求上返回带有后续索引的元素。

【讨论】:

  • 如果范围很小,这将非常有效。如果范围很大,您最终会分配一个巨大的临时数组。
  • 我赞成你的回答,但如果你的语言没有实现“随机播放”,很容易出错。请参阅robweir.com/blog/2010/02/microsoft-random-browser-ballot.html,了解一篇关于一个壮观例子的有趣文章。
  • 假设 a 是 3,b 是 7。取一个列表 [3, 4, 5, 6, 7]。将其随机播放(例如使用 Mark Byers 建议的 Fisher-Yates 算法),您将得到 [4, 7, 6, 5, 3]。比一个一个地取数字
  • 我觉得你的方法比我的效率高很多,谢谢你回答我的问题。
  • 我通常通过创建对象数组来进行随机播放。我为每个项目中我想要的信息添加了一个成员。我还添加了一个成员来存储随机数生成器的结果。然后,您按随机数对数组进行排序。简单可靠。
【解决方案2】:

由于您的样本大小几乎与您的愤怒大小相同,您可以只生成从 1 到 10 的所有整数,shuffle them 然后取前 8 个元素。

如果样本大小 (k) 远小于范围大小 (n),您可以使用 Fisher-Yates shuffle 的变体,在 k 步后停止算法,而不是对整个数组进行洗牌。

如果样本量很小但范围大小 [0,n) 太大而无法存储在内存中,那么您可以使用另一种变体,首先在 [0,n) 中选择一个随机数 s1。然后在 [0, n-1) 中选择一个数字,如果它等于或大于 s1,则在其上加一,得到 s2。然后在 [0, n-2) 中选择一个数字,并为 s1、s2 中的每一个加一,它大于或等于等等...

【讨论】:

    【解决方案3】:

    如果您的想法是获得 8 个随机数,您始终可以使用字典/哈希或列表(具有 Contains(int i) 方法),然后将字典或列表转换为数组:

    List<int> x = ...;
    int[] data = x.ToArray();
    

    【讨论】:

      【解决方案4】:
      List<Integer> list=new ArrayList<Integer>(8);
      
      while(int i <= 8){ 
        do {
          Integer n=randomGenerator(a,b); 
        } while (list.contains(n))
        list.add(n);
      } 
      

      当然,如果 a 和 b 之间没有至少 8 个不同的值,这将陷入无限循环。在开始之前我会为此设置一个陷阱。

      只有 8 个值,一个简单的 ArrayList 可能是最容易使用的东西。如果你有成百上千个值,为每个新条目遍历所有值可能会令人望而却步,你可能想要做一些更复杂的事情,比如使用 HashMap,或者保留一个单独的标志数组来说明所使用的值,或类似的。

      【讨论】:

        【解决方案5】:

        如果您的范围很小(或接近您要选择的元素数量),上面提出的解决方案很好。

        如果你的范围变大,一个更有效(和清晰)的方法如下:

        
            int[] pickRandom(int numberOfChoices, int lowerBound, int upperBound) {
              Set<Integer> choices = new HashSet<Integer>();
              while (choices.size() <= numberOfChoices) {
                choices.add(yourRandomGenerator (lowerBound, upperBound));
              }
              int[] ret = new int[choices.size()];
              int ii=0;
              for (Integer choice: choices) {
                ret[ii++] = choice.intValue();
              }
              return ret;
            }
        

        【讨论】:

          【解决方案6】:

          这里有一些很好的答案,但我要补充一个重要的警告:不要使用List,使用HashSet。掸掉我的计算机科学书呆子术语,检查一个元素是否已经存在于 List 中,运行时间为 O(n);用 HashSet 做同样的事情会给你 O(lg n) 的性能,这要快得多。对于小型数据集(例如 1 到 10 之间的 8 个数字),这很简单。对于大型数据集,它可以产生影响。

          应该这样做:

              HashSet resultSet = new HashSet();
              while (resultSet.size() < targetSize) {
                 resultSet.add(randomGenerator(a,b));
              }
          

          ...当然,在您的先决条件中进行健全性检查,以确保您的目标大小不超过您的范围。

          如果订单很重要,请在使用HashSet 确认它是新号码后将它们粘贴在List 中。或者只是将HashSet 转储到新的List 并随机播放。

          【讨论】:

            【解决方案7】:

            Collections 类中有一个内置的随机播放功能。

            例如

            List values = new ArrayList(); for( int i = 1; i < 10; i++ ) { values.add(i); } Collections.shuffle(values);

            【讨论】:

              猜你喜欢
              • 2017-06-06
              • 1970-01-01
              • 1970-01-01
              • 2019-01-12
              • 1970-01-01
              • 2013-03-05
              • 2011-05-16
              • 2018-05-03
              • 2013-03-13
              相关资源
              最近更新 更多