在 for 循环中交换整数数组值 - 这可能吗?

Swapping integer array values in a for loop - Is it possible?

所以我决定创建一个简单的卡片组洗牌程序,没有什么特别的只是一个包含 52 "cards" 编号从 0 到 52 的数组。我不确定这是否是最好的方法。

我创建了一个随机整数方法 (randInt) 来获取随机数,并创建了一个洗牌方法 (shuffle) 来获取两张随机卡片并交换它们的值。

我的方法很简单,但是当我 运行 代码(以及我添加的一些调试代码)时,我似乎让每个值都变成了完全相同的值 (d[2] = d[1] = randCard1) 这会导致同一张卡的倍数和其他明显的值完全消失。如果洗牌次数足够多,整副牌可能会变成 52 张全部由相同值组成的牌。

我已经阅读了一些关于交换整数数组的问题,但我的问题是不同的,因为它是关于使用 for 循环的问题,(因为我交换数组值的方法已经与那些问题相似,但是 final/static 关键字在我修改几次时没有帮助我得出结论是 for 循环是罪魁祸首)这显然会阻止数组正确更新。

是这种情况吗?如果是,我该如何克服?如果不是,我错过了什么?我交换整数数组值的方式还有其他问题吗?

这是我的代码:

import java.util.Random;

public class Cards {

    public static void main(String[] args) {

        int[] deck = new int[] {
            0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
            10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
            20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
            30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
            40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
            50, 51
        };

        printArray(deck, "Original Deck:");
        deck = shuffle(deck);
        printArray(deck, "Shuffled Deck:");
        }

        public static int[] shuffle(int[] d) {
            //shuffle between 100 to 200 to ensure a thorough shuffle
            int randLoops = randInt(100, 200);
            int randCard1;
            int randCard2;

        for (int i = 0; i <= randLoops; i++) {
            int temp;

            randCard1 = randInt(0, 51);

            do {randCard2 = randInt(0, 51);}
            while (randCard2 == randCard1);

            System.out.print("*" + randCard1 + "|" + randCard2 + "/");
            temp = randCard1;
            d[randCard1] = d[randCard2];
            d[randCard2] = d[temp];
            System.out.println(d[randCard1] + "|" + d[randCard2] + "*");
        }
        return d;
    }

    public static int randInt(int min, int max) {
        Random rand = new Random();    
        int randomNum = rand.nextInt((max - min) + 1) + min;

        return randomNum;
    }

    public static void printArray(int[] d, String t) {
        System.out.println(t);
        for (int i = 0; i < d.length; i++) {
                System.out.print(d[i] + ", ");
        }

        System.out.println();
    }
}

这是我的调试代码输出示例(希望它能有所帮助而不是阻碍):

Original Deck:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 
*40|41/41|41*
*29|40/41|41*
*19|26/26|26*
*2|27/27|27*
*4|30/30|30*
*24|25/25|25*
*7|1/1|1*
*17|47/47|47*
*14|5/5|5*
*42|11/11|11*
*23|42/11|11*
*33|30/30|30*
*19|42/9|9*
*11|26/9|9*
*40|21/9|9*
*36|11/9|9*     <--------- at the end I don't know why the values = 9?
Shuffled Deck:
9, 11, 30, 11, 30, 30, 31, 45, 11, 11, 51, 9, 11, 45, 45, 45, 51, 11, 9, 9, 44, 9, 30, 44, 27, 11, 9, 27, 31, 11, 11, 21, 11, 11, 45, 35, 9, 11, 11, 30, 9, 11, 9, 11, 21, 31, 9, 30, 45, 30, 11, 45, 
BUILD SUCCESSFUL (total time: 2 seconds)

这就是问题所在:

temp = randCard1;
d[randCard1] = d[randCard2];
d[randCard2] = d[temp];

您没有将卡值保存在临时文件中,而是保存了它的索引。你需要

temp = d[randCard1];
d[randCard1] = d[randCard2];
d[randCard2] = temp;

注意JDK有一个随机播放方法:

// create the deck
Integer[] deck = new Integer[52];
for (int i = 0; i < deck.length; i++) {
    deck[i] = i;
}

// shuffle it
Collections.shuffle(Arrays.asList(deck));

这真的是对滚动自己的洗牌算法的陷阱和测试需要的扩展评论。我将使用 Fisher-Yates 洗牌的 Collections.shuffle 应用于四元素列表。只有 24 种可能的结果,我可以在测试期间计算每个结果的实例数:

[1, 2, 0, 3] 4169320
[0, 3, 1, 2] 4169046
[0, 2, 1, 3] 4166184
[1, 3, 0, 2] 4166060
[2, 1, 0, 3] 4166150
[2, 3, 0, 1] 4169336
[0, 3, 2, 1] 4169641
[0, 1, 2, 3] 4165100
[2, 0, 1, 3] 4168724
[3, 2, 0, 1] 4169374
[2, 3, 1, 0] 4165930
[3, 1, 0, 2] 4167949
[1, 3, 2, 0] 4165973
[0, 2, 3, 1] 4165752
[1, 0, 2, 3] 4167152
[0, 1, 3, 2] 4164295
[3, 2, 1, 0] 4163534
[3, 0, 1, 2] 4165647
[1, 0, 3, 2] 4168772
[1, 2, 3, 0] 4163711
[3, 1, 2, 0] 4163498
[2, 0, 3, 1] 4166876
[2, 1, 3, 0] 4162543
[3, 0, 2, 1] 4169433

我做了同样的事情,使用了对该问题的评论中建议的带有随机比较器的排序想法。原始顺序及其相反顺序都出现得比应有的频繁得多。其他结果出现的频率要低得多。重点不在于具体的算法,而在于任何一种shuffle算法,即使听起来很合理,也需要进行分析和测试。

[1, 3, 0, 2] 3123183
[0, 3, 1, 2] 6248696
[0, 2, 1, 3] 1561055
[1, 2, 0, 3] 1564132
[2, 1, 0, 3] 4686711
[2, 3, 0, 1] 1562854
[0, 1, 2, 3] 18750411
[0, 3, 2, 1] 1562861
[2, 3, 1, 0] 4687112
[2, 0, 1, 3] 1562640
[3, 2, 0, 1] 1562653
[3, 1, 0, 2] 3123363
[0, 1, 3, 2] 6251613
[1, 0, 2, 3] 3125297
[1, 3, 2, 0] 1561043
[0, 2, 3, 1] 1564091
[3, 2, 1, 0] 17183252
[3, 0, 1, 2] 6251310
[1, 2, 3, 0] 1563693
[1, 0, 3, 2] 3126874
[2, 1, 3, 0] 4685909
[3, 1, 2, 0] 1565535
[2, 0, 3, 1] 1562618
[3, 0, 2, 1] 1563094

这是我的测试程序:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

public class Test {
  public static void main(String args[]) {
    Map<List<Integer>, Integer> resultMap = new HashMap<List<Integer>, Integer>();
    List<Integer> initial = new ArrayList<Integer>();
    initial.add(0);
    initial.add(1);
    initial.add(2);
    initial.add(3);
    for(int i=0; i<100000000; i++){
      List<Integer> working = new ArrayList<Integer>(initial);
      shuffle(working);
      //Collections.shuffle(working, rand);
      Integer oldCount = resultMap.get(working);
      if(oldCount == null){
        resultMap.put(working, 1);
      } else {
        resultMap.put(working, oldCount+1);
      }
    }
    for(Map.Entry<List<Integer>, Integer> entry : resultMap.entrySet()){
      System.out.println(entry.getKey().toString()+" "+entry.getValue());
    }
  }

  static Random rand = new Random(3);
  static Comparator<Integer> comp = new Comparator<Integer>() {
    @Override
    public int compare(Integer arg0, Integer arg1) {
      return rand.nextInt(2) - 1;
    }
  };

  static void shuffle(List<Integer> in) {
    Collections.sort(in, comp);
  }
}