我在大学里做了一项练习,其中一部分包括制作一包必须洗牌的卡片。我把卡片放在一个阵列中(没有洗牌)并且想要将它们洗牌并将它们推到自制的堆栈上,我可以从中弹出卡片来处理它们。
我的问题是我想检查我生成的随机数(以及代表阵列中的一张卡)是否已经在堆栈中。从阅读这个论坛我已经得到了下面的代码,在我看来应该工作。在调试虽然我注意到重复。
根据我在下面的评论,我们无法使用收藏框架(编辑)
private Stack<Card> deck;//to hold cards
private Card[] protoDeck;//to hold cards before shuffling
private Random randomer;
private int cardsDealt;//how many cards used. Used for other methods
private static final int TOTALCARDS = 52;//sets limit of deck for all decks
public void shuffle(){//remove cards from deck and put back in random order
randomer = new Random();
int[] temp = new int[TOTALCARDS];//to keep track of random numbers
int rand = 0;
for (int i = 0; i < temp.length ; i++) {
do {//keep creating randoms if
rand = randomer.nextInt(TOTALCARDS);
deck.push(protoDeck[rand]);//puts the Card onto the Deck in a random position
temp[i] = rand;
} while (!(Arrays.asList(temp).contains(rand)));//check if the number already used
}
}
@PeterLawrey我已经稍微调整了代码,因为我只需要将整个套牌洗牌并且它有效,我将从堆栈中弹出卡片来处理
public void shuffle() {
randomer = new Random();
for(int i = 0; i < TOTALCARDS; i++) {
// pick a random card from the rest of the deck
int j = randomer.nextInt(protoDeck.length - i) + i;
// swap cards
Card tmp = protoDeck[i];
protoDeck[i] = protoDeck[j];
protoDeck[j] = tmp;
deck.push(protoDeck[i]);
}
}
感谢彼得和所有其他贡献者。微米。
答案 0 :(得分:3)
从
开始private final Card[] deck;//to hold cards before shuffling
private final Random rand = new Random();
你可以做到
public void shuffle() {
// no need the shuffle the last card.
shuffle(deck.length - 1);
}
// will leave the first N card random without duplicates.
public void shuffle(int numberOfCards) {
for(int i = 0; i < numberOfCards; i++) {
// pick a random card from the rest of the deck
int j = rand.nextInt(protoDeck.length - i) + i;
// swap cards
Card tmp = deck[i];
deck[i] = deck[j];
deck[j] = tmp;
}
}
成本为O(N),其中N是随机卡的数量。
想象一下你有一个像
这样的小甲板AS AC AD AH 2S 2C 2D 2H
你需要随机选择第一张牌,你从牌组中选择一张并交换该牌。说nextInt()是5 =&gt; 2C
2C | AC AD AH 2S AS 2D 2H
桌子由随机选择的卡+未选中。你没有重复,因为相同的卡被移动。下一张随机卡是2H,与AC交换
2C 2H | AD AH 2S AS 2D AC
最后恰好选择了AD。
2C 2H AD | AH 2S AS 2D AC
这会给你三张随机卡,其余的。同一个数组可以再次使用,因为从排序或随机套牌开始,不会使结果或多或少随机。
如果有123,则回答Why does this simple shuffle algorithm produce biased results?,可能的结果是
123
+- 123 - swap 1 and 1 (these are positions, not numbers)
| +- 123 - swap 2 and 2
| +- 132 - swap 2 and 3
+- 213 - swap 1 and 2
| +- 213 - swap 2 and 2
| +- 231 - swap 2 and 3
+- 321 - swap 1 and 3
+- 321 - swap 2 and 2
+- 312 - swap 2 and 3
正如您所看到的,只有6种可能的结果,所有结果都是同样可能的。
答案 1 :(得分:1)
实际上Stack扩展了Vector。因此,您可以使用contains方法检查已存在的元素是否存在。
答案 2 :(得分:1)
最初的问题是Arrays.asList(temp)
不会创建List<Integer>
而是创建List<int[]>
。
因此Arrays.asList(temp).contains(rand)
始终返回false
。
如果您使用了包装类Integer
(Integer[] temp = new Integer[TOTALCARDS];
),它会起作用,但是您的方法效率非常低,因为您必须在集合中生成“随机”数字,这将减少每次迭代。
一种方法是创建一个包含位置0到51的数组,对其进行随机播放,然后遍历它以推动卡片中的卡片。
public void shuffle(){//remove cards from deck and put back in random order
int[] temp = new int[TOTALCARDS];//to keep track of random numbers
for(int i = 0; i < temp.length; i++){
temp[i] = i;
}
//shuffle the array
for (int i = 0; i < temp.length ; i++) {
deck.push(protoDeck[temp[i]]);
}
}
这种方法在O(n)时间内运行。
答案 3 :(得分:0)
也许我弄错了,但我认为你的概念很糟糕。
听起来像是错误的订单。另一方面,如果你想要独特的元素,使用Set总是有效。
答案 4 :(得分:-1)
在@ ZouZou州,Arrays.asList(temp)
返回List<int[]>
。你可能会这样做是因为answer引起的混乱(顺便说一句是错的)。这个answer显示了一种使用二进制搜索的方法:
public boolean contains(final int[] array, final int key)
{
Arrays.sort(array);
return Arrays.binarySearch(array, key) >= 0;
}
这会修改传入的数组。你可以选择复制数组并处理原始数组,即int[] sorted = array.clone();
但这只是短代码的一个例子。运行时为O(NlogN)
。
根据Java文档,binarySearch将返回以下内容之一(我强调了重点):
搜索键的索引(如果它包含在列表中);否则,( - (插入点) - 1)。 插入点定义为将键插入列表的点:第一个元素的索引大于键,或者list.size(),如果所有元素都在列表小于指定的密钥。请注意,当且仅当找到密钥时,这可以保证返回值>> =。