随机卡生成

时间:2010-08-05 14:14:47

标签: java

我需要从数组中随机生成三张牌我有从card1到card52的52张牌的阵列

String rank[]=new String[52];
for(int i=0;i<rank.length;i++)
{
rank[i]= "card"+i;
}

现在我需要从阵列中选择三张牌,它不应该是可重复的。

任何人都可以帮助我。实际上我在做这个bt卡正在重复。 请给我解决方案。

先谢谢。

6 个答案:

答案 0 :(得分:15)

您可以尝试Collections.shuffle(List list)方法:

String rank[] = new String[52];
for (int i = 0; i < rank.length; i++) {
  rank[i] = "card" + i;
}
List<String> cards = Arrays.asList(rank);
Collections.shuffle(cards);
List<String> selectedCards = cards.subList(0, 3);

答案 1 :(得分:8)

如果您将数组转换为List,则可以使用Collections.shuffle()对其进行随机化。然后,如果您只是获取列表的前三个条目,您将获得三张没有重复的随机卡。

List<String> ranklist = Arrays.asList(rank);
Collections.shuffle(ranklist);
String rank1 = ranklist.get(0);
String rank2 = ranklist.get(1);
String rank3 = ranklist.get(2);

答案 2 :(得分:1)

可能比整个阵列更快的东西:

java.util.Random r = new java.util.Random();
int c1 = r.nextInt(52),
  c2 = r.nextInt(51),
  c3 = r.nextInt(50);
if(c2 >= c1) c2++;
if(c3 >= Math.min(c1, c2)) c3++;
if(c3 >= Math.max(c1, c2)) c3++;
System.out.println("Card 1: " + rank[c1]);
System.out.println("Card 2: " + rank[c2]);
System.out.println("Card 3: " + rank[c3]);

事实上,我使用this algorithmCollections.shuffle(屏幕截图here)的广义(较慢)形式进行的一些时序测试表明此方法约3.7次3张卡更快,实际上选择最多24张随机卡的速度更快。

向那些怀疑的人解释算法:

概率

我们选择随机数 - 首先是52中的一个。如果我们要删除那张卡然后选择另一张,那将是51中的一个...所以我们可以选择我们选择的索引的随机数范围。

如果我们从数组中挑选和删除,那么我们只取出索引1处的项目,然后取出索引2处的项目,并将索引3取出。

我上面所做的是调整索引以使其与从数组中取出项目具有相同的效果。

对于索引2,我们有一个数字,可以是0到50之间的任何数字。但是,我们假装我们在索引6处拿出了卡片......

这意味着我们现在想要在0-5和7-51范围内均匀分布一个随机数而不是0到50范围内的随机数。这仍然是51种可能性。我们通过在第二个索引中加1来实现,如果它是&gt; = 6.现在我们有一个正确范围内的数字,正确的分布和相同的概率,如果点击任何允许的索引。

同样稍微复杂的逻辑用于第三张牌:牌组中有两个“缺失”点 - 所以我们调整第三个索引以覆盖可用范围。首先,如果它等于或高于第一个缺失位置,则将其向上移动。然后,如果它等于或高于秒,则再次将其向上移动。这并不会将选择偏向更高的值 - 我们所做的就是避免使用已经使用过的索引。

概率没有偏差。

效率

在评论中提到,该算法和使用Collections.shuffle的算法具有相同的复杂度(即O(n)),并且该方法的可读性稍差。要做的第一点是该算法更多复杂;即,为了使整个阵列混洗,它是O(n ^ 2)。对于低n,该算法更有效。并且,我认为效率的差异保证了可读性的牺牲。比较:

<强> Collections.shuffle

  1. 选择随机数
  2. 从列表中删除项目
  3. 将项目插入列表
  4. 再重复51次
  5. 此方法

    1. 选择随机数
    2. 选择随机数
    3. 选择随机数
    4. 最多3个增量
    5. 这忽略了在使用第一种方法时从数组到Container的转换。不可避免的结论是这种方法效率明显提高。

      顺便说一句 - 当您考虑挑选4张牌时,您可以看到O(n ^ 2)性质 - 这需要最多6个增量... 5张牌,最多10张... 6张牌,最多15张...对于n,(n ^ 2 - n)/ 2

      要概括

      在这个问题中,我使用了Math.minMath.max作为对2个项目列表进行排序的简单方法。在通用情况下(即选择'n'[1-52包含]非重复随机卡),我们需要对最多52个项目的列表进行排序。这可以在O(n)最坏的情况下使用插入排序,通过保持所选索引的有序列表来完成。选择新的随机索引由

      完成
      1. 使用Random.nextInt(52 - selectedIndexListSize)
      2. 选择新的随机索引
      3. 迭代排序列表,在每个节点递增我们选择的索引,如果它是> = =节点值,如果它更少则停止
      4. 在数组
      5. 中选定索引处输出卡片
      6. 将我们选择的索引插入排序列表中,在我们停止的位置
      7. 每个选择都是O(n) - 但最多可以选择52个选项,这使得它成为O(n ^ 2)。

        然而,就效率而言,只要m ^ 2

答案 3 :(得分:1)

        Random random = new Random();
        List<Integer> randomList = new ArrayList<Integer>();
        int randomInt;

        do {
            randomInt = random.nextInt(52);
            if (randomList.contains(new Integer(randomInt)))
                continue;
            randomList.add(randomInt);
        } while (randomList.size() < 3);

randomList将包含三张卡的索引

答案 4 :(得分:0)

有一个数组(甚至是一个字符串)并在您选择卡时添加它。这样,无论何时选择第二张或第三张卡,如果它在数组(或字符串)中,您都可以选择另一张卡。

这是一种方法......我没有检查它是否有效。

String pickedCards = ""
int totalPickedCards = 0
boolean continue = true;
for(continue) 
{
  tempVariable = pickedCard
  if (pickedCard.contains("/"+tempVariable+"/") == false) { // if you didn't already pick it then
    pickedCards = pickedCards + "/" + tempVariable + "/";
    // save the card you picked - stored in tempVariable
    ++totalPickedCards
  }
  if (totalPickedCards >= 3) { // exit loop if you have 3 cards picked
    continue = false;
  }
}

答案 5 :(得分:0)

基本上有两种数学上有效的方法:

  1. 正如其他人所建议的那样,将整个数组洗牌,然后从头开始依次选择。

  2. 随机挑选第一个。然后随机挑选第二个。如果第二个与第一个相同,则再次随机选择。即将选择放入一个循环中继续尝试,直到它获得之前未选择的值。对于第三个,您必须检查前两个,等等。您可能想要创建一组平行于卡片列表的标记,以指示已经选择的,或者您可以在选择后将卡片更改为null,等等

  3. 如果您要使用大部分卡片,那么#p#效率会更高。如果你要使用一小部分卡片,#2会更有效率。