【发布时间】:2009-08-11 19:44:13
【问题描述】:
我在 Wikipedia 找到了这段 Java 代码,它应该对数组进行适当的洗牌:
public static void shuffle (int[] array)
{
Random rng = new Random();
int n = array.length;
while (n > 1)
{
n--;
int k = rng.nextInt(n + 1);
int tmp = array[k];
array[k] = array[n];
array[n] = tmp;
}
}
虽然我没有测试代码,但看起来它应该可以很好地处理数组。在我的 C# 项目中,我创建了一个 CardSet 类并在 Shuffle() 方法中使用了上面的代码:
public class CardSet
{
private List<Card> cards;
public Card this[int i]
{
get { return cards[i]; }
set { cards[i] = value; }
}
public void Shuffle()
{
Random rng = new Random();
int n = this.NumberOfCards;
while (n < 1)
{
n--;
int k = rng.Next(n + 1);
Card tmp = this[k];
this[k] = this[n];
this[n] = tmp;
}
}
但是,当我使用该方法时,不会发生改组:
CardSet cs = new CardSet();
cs.Shuffle();
foreach (Card c in cs)
{
Console.WriteLine(c.ToString());
}
我只是想不通为什么它不起作用。我认为 List 可能会自动对其对象进行排序,因此我尝试更改其值之一,
cs[8] = new Card(Suites.Hearts, Numbers.Two);
Card 正是我放的地方。要么我犯了一些简单的错误,要么我没有正确编写洗牌算法。如果我提供的代码看起来不错,并且有人认为错误可能在我的代码中的其他地方,我可以提供我的其余代码。
【问题讨论】:
-
1) 这个洗牌功能很差。 2)你为什么要解除这么简单的方法而不是自己写?
-
@Spencer - 即使您可以轻松推出自己的解决方案,检查其他人对常见问题的解决方案总是值得的。你可能只是学到了一些东西。诀窍是能够区分好的和坏的实现。
-
我想先让一个简单的函数工作。接下来我想我会尝试使用 RNGCrypoServiceProvider 或 Fredou 链接中的 GUID
-
@Spencer:洗牌一点也不差,它实际上是洗牌现有列表的最佳方法。它保证每张牌都有相同的机会出现在牌组中的每个位置,并且它用尽可能少的工作量来做到这一点。改进算法的唯一方法是使用具有更好随机性的随机生成器。如果你想要一个好的算法,问问你自己:WWKD (What Will Knuth Do)。
-
这看起来是一个 Knuth-Fisher-Yate 洗牌,没有严重的问题(假设 PRNG 不错,这完全是另一回事)。请参阅 Jeff Atwood 对此的启示:codinghorror.com/blog/archives/001015.html