【问题标题】:Getting 10 random integers without repetition? [duplicate]获得10个随机整数而不重复? [复制]
【发布时间】:2015-05-18 08:12:27
【问题描述】:

我正在开发一个小程序,它显示一副 52 张卡片中的 10 张随机卡片。我使用 for 循环循环浏览 10 张卡片,并从我下载的图像中随机给它们一张卡片。当我编译和运行小程序时,有时会重复。有人可以告诉我如何在不重复的情况下解决这个问题吗?

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Color; 
import java.util.Random;

public class Unit12Assignment1 extends Applet
{ 
     Image card[] = new Image[10];

public void init()
{
    String deckImages[] = {"cards_gif/c1.gif", "cards_gif/c2.gif", "cards_gif/c3.gif", "cards_gif/c4.gif",
        "cards_gif/c5.gif", "cards_gif/c6.gif", "cards_gif/c7.gif", "cards_gif/c8.gif", "cards_gif/c9.gif", 
        "cards_gif/c10.gif", "cards_gif/cj.gif", "cards_gif/ck.gif", "cards_gif/cq.gif",
        "cards_gif/s1.gif", "cards_gif/s2.gif", "cards_gif/s3.gif", "cards_gif/s4.gif",
        "cards_gif/s5.gif", "cards_gif/s6.gif", "cards_gif/s7.gif", "cards_gif/s8.gif",
        "cards_gif/s9.gif", "cards_gif/s10.gif", "cards_gif/sj.gif", "cards_gif/sk.gif",
        "cards_gif/sq.gif", "cards_gif/d1.gif", "cards_gif/d2.gif", "cards_gif/d3.gif",
        "cards_gif/d4.gif", "cards_gif/d5.gif", "cards_gif/d6.gif", "cards_gif/d7.gif",
        "cards_gif/d8.gif", "cards_gif/d9.gif", "cards_gif/d10.gif", "cards_gif/dj.gif",
        "cards_gif/dk.gif", "cards_gif/dq.gif", "cards_gif/h1.gif", "cards_gif/h2.gif",
        "cards_gif/h3.gif", "cards_gif/h4.gif", "cards_gif/h5.gif", "cards_gif/h6.gif",
        "cards_gif/h7.gif", "cards_gif/h8.gif", "cards_gif/h9.gif", "cards_gif/h10.gif",
        "cards_gif/hj.gif", "cards_gif/hk.gif", "cards_gif/hq.gif"};

    for( int i = 0; i < card.length; i++ )
    {
        int x = (int)(Math.random() * 52);
        card[i] = getImage(getDocumentBase(), deckImages[x]);
    }

}

public void paint(Graphics g)
{
    setBackground( Color.green );
    int x = -60;

    for( int i = 0; i < card.length / 2; i++ )
    {
        x = x + 90;
        g.drawImage(card[i], x, 30, this);
    }

    x = -60;

    for( int i = card.length / 2; i < card.length; i++ )
    {
        x = x + 90;
        g.drawImage(card[i], x, 150, this);
    }
}
}

【问题讨论】:

标签: java for-loop random


【解决方案1】:

有多种可能性。您可以检测重复性,并在这种情况下生成新索引,直到获得唯一索引。其他选项可以是随机排列一组索引,然后取前 10 个。要有创意,这不是一项艰巨的任务。

另一种可能性:

// TODO initialize this to -1
int chosen[] = new int[10];
    for( int i = 0; i < card.length; i++ )
    {
      int x = (int)(Math.random() * 52);

      for(int j=0; j< chosen.length; j++)
        if(x==chosen[j])
        {
          x++;
          j=0;
          if(x>51)
            x=0;
        }
        card[i] = getImage(getDocumentBase(), deckImages[x]);
        chosen[i] = x;
    }

这不是严格随机的,但你可以确定它确实会结束,即使你遇到一个随机数生成器,其实现方式如下:return 42;

【讨论】:

    【解决方案2】:

    由于随机生成器,卡片被选中。为避免重复,您也可以存储该轮之前生成的数字。因此,您可以强制生成器选择一个新号码,因为它通过将选择的号码与之前的号码进行比较来选择一个新号码。

    【讨论】:

      【解决方案3】:

      它被称为 Fisher-Yates shuffle(或 Fisher-Yates-Knuth shuffle)。基本上相当于从59个彩票球中选出6个中奖。 链接到描述http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

      伪代码(更接近C++,希望不要犯很多错误)

      void swap(int& a, int& b) {
          int t = a;
          a = b;
          b = t;
      }
      
      // in-place shuffle
      void shuffle(int cards[], int n) { // sample n non-repeating cards from the deck
          int last_index = 51;
          for(int k = 0; k != n; ++k) {
              int idx = random(last_index); // random shall produce number from 0 to last_index inclusively
              if (idx != last_index) {
                  swap(cards[idx], cards[last_index]);
              }
              --last_index;
          }
      }
      
      int cards[52];  
      
      for(int k = 0; k != 52; ++k) {
          cards[k] = k;
      }
      
      shuffle(cards, 10);
      
      // now last 10 positions in cards array are sampled cards 
      

      【讨论】:

      • 当Java提供Collections.shuffle()时,不应该提倡自己实现。
      • @pjs Collections.shuffle() 显然是错误的答案。它同时洗牌所有卡片,这不是@Tedion 所要求的。请归还我的布朗尼积分,下次仔细阅读所问的内容和答案,谢谢
      • 你第一线提倡费舍尔-耶茨洗牌,这正是Collections.shuffle() 实现的。如果您不希望整套洗牌,那么Floyd's subset selection 是更好的选择。
      • @pjs 不,不是。如果有一个接口 Collection.partial_shullfe(int n),那将是一个很好的答案。你被要求选择整个集合的子集,你提出的答案是洗牌整个集合,因为有一个方便的功能。请下次仔细阅读所问的内容和回答的内容,谢谢。
      • 自己尝试仔细阅读。问题是在 Java 中,而不是在 Java 中的“解决方案”你“希望”不包含很多错误是一个糟糕的答案。我提出的答案(在链接的问题中)是使用弗洛伊德的算法,并使用被询问的语言。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-24
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 2017-10-09
      • 2015-07-12
      相关资源
      最近更新 更多