Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 洗牌一副牌,交换两个值后的冗余_Java - Fatal编程技术网

Java 洗牌一副牌,交换两个值后的冗余

Java 洗牌一副牌,交换两个值后的冗余,java,Java,我被要求编写一个程序(主要是一种方法)来洗牌。我编写了以下程序: public class Deck { //////////////////////////////////////// // Data Members //////////////////////////////////////// private Card[] cards; // array holding all 52 cards private int cardsInDeck; // the current numbe

我被要求编写一个程序(主要是一种方法)来洗牌。我编写了以下程序:

public class Deck {

////////////////////////////////////////
// Data Members
////////////////////////////////////////

private Card[] cards; // array holding all 52 cards
private int cardsInDeck; // the current number of cards in the deck

public static final int DECK_SIZE = 52;

/**
 * Shuffles the deck (i.e. randomly reorders the cards in the deck). 
 */
public void shuffle() {
    int newI;
    Card temp;
    Random randIndex = new Random();

    for (int i = 0; i < cardsInDeck; i++) {

        // pick a random index between 0 and cardsInDeck - 1
        newI = randIndex.nextInt(cardsInDeck);

        // swap cards[i] and cards[newI]
        temp = cards[i];
        cards[i] = cards[newI];
        cards[newI] = temp;
    }
}

}
公共类甲板{
////////////////////////////////////////
//数据成员
////////////////////////////////////////
私人卡[]卡;//存储所有52张卡的阵列
private int cardsInDeck;//牌组中当前的牌数
公共静态最终内部甲板尺寸=52;
/**
*洗牌牌组(即随机重新排列牌组中的牌)。
*/
公开无效洗牌(){
int newI;
卡片温度;
Random randIndex=新的Random();
对于(int i=0;i
但是在上面的洗牌方法中有一个逻辑错误,如下所示:假设我用42号卡替换4号卡,那么我正在交换 两次。我想知道有没有办法不这样做

我在这里查看了一个帖子:


但这对我来说毫无意义。

您可以将您的实现与Collections.shuffle进行比较。shuffle,这绝对是一个正确的实现,这是src的一个片段

  // Shuffle array
  for (int i=size; i > 1; i--)
      swap(arr, i-1, rnd.nextInt(i));

...

   private static void swap(Object[] arr, int i, int j) {
        Object tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
我想知道有没有办法不这样做

当然。与其将一张卡换成另一张卡,只需将一张卡换成另一张卡即可

所以,在任何时候,你都可以从“所有剩余的牌”中挑选出哪张牌会在插槽
i
,而这些牌都没有被挑选出来。这在概念上相当于从一张牌列表开始,然后随机移除牌以放入新的洗牌集合。事实上,你实际上是在交换位置,而你这样做是无关的,因为在任何时候,你都会从剩余的插槽中均匀随机地挑选

有关更多信息,请阅读

(一些实现从末尾交换,因此元素
x
与范围
[0,x]中的随机元素交换。)
。这相当于我所描述的,只是镜像。就我个人而言,我发现在任何时候都更容易将集合的第一部分视为洗牌部分,但这是我的一个缺点,而不是固有的差异。)


还请记住,如果使用
列表
,则可以使用并避免为此编写代码。

有时,洗牌的最佳方法是不要洗牌。由于您已经知道如何使用随机数,因此可以使用对Fisher-Yates shuffle的修改,以随机顺序提取卡牌,无需重复,无需初始排序

用这些物理术语来考虑(当使用一副真正的牌时)。与其先洗牌,然后继续取出最上面的牌,只需将牌组按顺序排列,每次从随机位置取出一张牌即可

请参阅,以获得有关其工作原理的完整解释,但我将在下面介绍从1到9中提取三个数字


从(未缓冲的)列表
{1,2,3,4,5,6,7,8,9}
(显然长度为9)开始,并基于该长度生成一个随机数(从0到8,包括0到8,假设我们使用基于零的索引,Java就是这样做的)。假设第一个随机数是4

然后将项目保存在位置4(即
5
)处,并将列表中的最后一个项目(
9
)移动到该位置,将长度减少1。这将为您提供长度为8的
{1,2,3,4,9,6,7,8}

然后使用基于长度的随机数(0到7,包括0到7)再次返回第二个数字。在这种情况下,我们将得到随机数1

偏移量1处的项目是
2
,然后我们调整列表,调整与第一步相同,给出长度为7的
{1,8,3,4,9,6,7}

现在假设我们得到了第三个基于当前长度7的随机数,它又恰好是4。该项现在是
9
,因此我们在将列表修改为长度为6的
{1,8,3,4,7,6}
后返回该项


您应该能够看到这是如何发展的。不必担心预先对整个列表进行排序,您可以实现一个随机序列(好的,随机数生成器允许的随机序列),而无需重复。

据我所知,这几乎就是在数组中交换两个元素的方式(至少对Java而言)@MadProgrammer:进行交换的三行很好,但洗牌的一般方法并非如此。幸运的是,它很容易被修复。@JonSkeet我不得不把头撞在墙上几分钟,但我明白你的意思,OP在每次迭代中都会洗牌“整个”列表,他们真的应该洗牌一个不断缩小的范围。。。清澈如泥;)使用Fisher-Yates。这种方法被证明不是均匀分布。为什么需要将最后一个移动到该位置?“只需删除项目就行了。”狗仔队,答案只假设一个简单的数组,所以没有删除操作符。如果您有一个向量类型的集合,它的效率可能会降低,因为上面的项都被下移了。