c # переход по ссылке Фишер-Йейтс Шаффлер - PullRequest
1 голос
/ 22 августа 2011

Я пытаюсь использовать алгоритм Фишера-Йейтса, чтобы перетасовать стек элементов.У меня проблемы с передачей в стек по ссылке.Код ниже выдает ошибку «Итераторы не могут иметь параметры ref или 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;
        }
    }
}

}

Ответы [ 3 ]

7 голосов
/ 22 августа 2011

Как заставить алгоритм работать с реальным стеком, который передается в

Вы не нуждаетесь здесь в параметре ref, поскольку Stack<T> является типом ссылки, и вы не пытаетесь переназначить саму ссылку.

Ссылки по умолчанию передаются по значению, но это значение (ссылка) указывает на один и тот же объект в куче, другими словами, у вас есть две ссылки, указывающие на один и тот же объект, что нормально - все операции будут выполняться с оригиналом Stack<T> объект.

Edit:

В свете вашего комментария я предлагаю вам редизайн, чтобы не изменять исходный 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 - возможно, вы захотите передать его. На этом этапе вы можете использовать реализацию 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();
4 голосов
/ 22 августа 2011

Стек не обязательно должен передаваться по ссылке, потому что ссылочные типы (например, Stack<T>) уже передаются по ссылке.Единственная причина использовать модификаторы ref или out в параметре ссылки - это если вы действительно хотите изменить саму ссылку (например, создать новую Stack<T> и назначить ее параметру как своего рода альтернативный метод возврата- так же, как двойные указатели в С).

1 голос
/ 22 августа 2011

Так как Stack - это класс, я не думаю, что в этом случае вам нужно ключевое слово ref.
Это должно работать без него.

...