c#通过引用传递Fisher-Yates Shuffler
本文关键字:Fisher-Yates Shuffler 引用 | 更新日期: 2023-09-27 18:06:29
我正在尝试使用Fisher-Yates算法来洗牌一堆元素。我在通过引用传递堆栈时遇到了麻烦。下面的代码给出了错误"迭代器不能有refor out形参"。我如何让算法对传入的实际堆栈起作用?
谢谢。
代码如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public static class Doshuffle
{
public static IEnumerable<T> Shuffle<T>(ref Stack<T> source)
{
Random rng = new Random();
T[] elements = source.ToArray();
source.Clear();
// Note i > 0 to avoid final pointless iteration
for (int i = elements.Length - 1; i > 0; i--)
{
// Swap element "i" with a random earlier element it (or itself)
int swapIndex = rng.Next(i + 1);
T tmp = elements[i];
elements[i] = elements[swapIndex];
elements[swapIndex] = tmp;
}
// Lazily yield (avoiding aliasing issues etc)
foreach (T element in elements)
{
source.Push(element);
yield return element;
}
}
}
}
我如何让算法对传递的实际堆栈起作用在吗?
不需要这里的ref
参数,因为Stack<T>
是一个引用类型,您不试图重新分配引用本身。
引用在默认情况下是按值传递的,但是这个值(引用)指向堆上的同一个对象,换句话说,你有两个引用指向同一个对象,这很好-所有的操作都将在原始Stack<T>
对象上执行。
根据你的评论,我建议你重新设计,不要修改原来的Stack<T>
,这是麻烦的开始:
public static IEnumerable<T> Shuffle<T>(Stack<T> source)
{
Random rng = new Random();
T[] elements = source.ToArray();
// Note i > 0 to avoid final pointless iteration
for (int i = elements.Length - 1; i > 0; i--)
{
// Swap element "i" with a random earlier element it (or itself)
int swapIndex = rng.Next(i + 1);
T tmp = elements[i];
elements[i] = elements[swapIndex];
elements[swapIndex] = tmp;
}
// Lazily yield (avoiding aliasing issues etc)
foreach (T element in elements)
{
yield return element;
}
}
现在你可以这样使用:
foreach (var item in Doshuffle.Shuffle(gameDeck))
{
System.Console.WriteLine(item.cardName);
}
也要小心使用Random
-您可能想要传递它。在这一点上,您可以使用Jon Skeet的Shuffle实现而不是您自己的——重用比重新发明要好。
最后编辑:
看起来你只是想打乱你的Stack<T>
到位-使用扩展方法代替:
public static void Shuffle<T>(this Stack<T> source)
{
Random rng = new Random();
T[] elements = source.ToArray();
source.Clear();
// Note i > 0 to avoid final pointless iteration
for (int i = elements.Length - 1; i > 0; i--)
{
// Swap element "i" with a random earlier element it (or itself)
int swapIndex = rng.Next(i + 1);
T tmp = elements[i];
elements[i] = elements[swapIndex];
elements[swapIndex] = tmp;
}
foreach (T element in elements)
{
source.Push(element);
}
}
现在你可以这样做:
gameStack.Shuffle();
堆栈不需要像这样通过引用传递,因为引用类型(如Stack<T>
)已经通过引用传递了。在引用形参上使用ref
或out
修饰符的唯一原因是,如果您想实际修改引用本身(例如创建一个新的Stack<T>
并将其赋值给该形参作为一种替代返回方法——与C中的双指针相同)。
由于Stack是一个类,我认为在这种情况下不需要ref关键字。