C#传递按引用费雪耶茨洗牌费雪

2023-09-11 06:45:57 作者:爱我就别丢下我。

我试图使用费雪耶茨算法洗牌一叠元素。我在通过引用传递栈中的麻烦。下面的code给出了错误迭代器不能有ref或out参数。我如何获得该算法作用于获取传递,在实际栈?

感谢。

code是如下。

 使用系统;
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;

命名空间ConsoleApplication1
{
公共静态类Doshuffle
{
    公共静态的IEnumerable< T>随机< T>(REF堆栈< T>源)
    {

        随机RNG =新的随机();
        T []元素= source.ToArray();
        source.Clear();
        //注意I> 0,以避免最终毫无意义的重复
        对于(INT I = elements.Length  -  1; I> 0;我 - )
        {
            //交换元件我与一个随机早期的元素它(或自己)
            INT swapIndex = rng.Next第(i + 1);
            牛逼TMP =元素[I]
            元素[I] =元素[swapIndex]
            元素[swapIndex] = TMP;
        }
        //懒洋洋地产生(避免混淆的问题等)
        的foreach(在元件T元素)
        {
            source.Push(元);
            得到的回报元素;
        }
    }
}
 

}

解决方案   

我如何获得该算法作用于获取传递的实际堆栈   在?

您做的不可以需要 REF 参数,在这里,因为堆栈< T> 是引用类型,你是不是要重新分配的基​​准本身。

引用默认情况下按值传递的,但该值(参考)指向堆上的同一个对象,换句话说,你有两个引用指向同一个对象,这是很好的 - 所有的操作将在原有基础上执行堆栈< T> 对象

编辑:

鉴于您的评论的,我建议你重新设计不修改原来的堆栈< T> 这是麻烦的开始:

 公共静态的IEnumerable< T>随机< T>(堆栈< T>源)
{
    随机RNG =新的随机();
    T []元素= source.ToArray();
    //注意I> 0,以避免最终毫无意义的重复
    对于(INT I = elements.Length  -  1; I> 0;我 - )
    {
        //交换元件我与一个随机早期的元素它(或自己)
        INT swapIndex = rng.Next第(i + 1);
        牛逼TMP =元素[I]
        元素[I] =元素[swapIndex]
        元素[swapIndex] = TMP;
    }
    //懒洋洋地产生(避免混淆的问题等)
    的foreach(在元件T元素)
    {
        得到的回报元素;
    }
}
 
C 基础加强第二天

现在你可以使用这样的:

 的foreach(在Doshuffle.Shuffle(gameDeck VAR项目))
{
   的System.Console.WriteLine(item.cardName);
}
 

另外要小心你使用随机 - 你可能想通过它在这一点上,你可以使用Jon飞碟双向的洗牌实施,而不是你自己 - 这是更好的重用不是重复

最后编辑:

看起来你只是想打乱你的堆栈< T> 到位 - 使用扩展方法来代替:

 公共静态无效的随机< T>(这个堆栈< T>源)
{
    随机RNG =新的随机();
    T []元素= source.ToArray();
    source.Clear();
    //注意I> 0,以避免最终毫无意义的重复
    对于(INT I = elements.Length  -  1; I> 0;我 - )
    {
        //交换元件我与一个随机早期的元素它(或自己)
        INT swapIndex = rng.Next第(i + 1);
        牛逼TMP =元素[I]
        元素[I] =元素[swapIndex]
        元素[swapIndex] = TMP;
    }
    的foreach(在元件T元素)
    {
        source.Push(元);
    }
}
 

现在,你可以这样做:

  gameStack.Shuffle();
 

I am trying to use the Fisher-Yates algorithm to shuffle a stack of elements. I'm having trouble passing in the stack by reference. The code below gives the error "Iterators cannot have ref or out parameters". How do I get the algorithm to act on the actual stack that gets passed in?

Thanks.

Code is below.

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;
        }
    }
}

}

解决方案

How do I get the algorithm to act on the actual stack that gets passed in?

You do not need a ref parameter here since Stack<T> is a reference type and you are not trying to re-assign the reference itself.

References are by default passed by value but that value (the reference) points to the same object on the heap, in other words you have two references pointing to the same object which is fine - all operations will be executed on the original Stack<T> object.

Edit:

In light of your comment I suggest you redesign to not modify the original Stack<T> which is troublesome to begin with:

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;
    }
}

Now you can just use it like this:

foreach (var item in Doshuffle.Shuffle(gameDeck)) 
{ 
   System.Console.WriteLine(item.cardName); 
}

Also be careful with your use of Random - you might want to pass it in. At this point you can use Jon Skeet's Shuffle implementation instead of your own - it's better to reuse than reinvent.

Final Edit:

It looks like you just want to shuffle your Stack<T> in place -use an extension method instead:

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);
    }
}

Now you can just do:

gameStack.Shuffle();