C #: хорошая / лучшая реализация метода Swap - PullRequest
10 голосов
/ 16 февраля 2009

Я прочитал этот пост о перестановке карт , и во многих алгоритмах перестановки и сортировки вам нужно поменять местами два элемента в списке или массиве. Но как выглядит хороший и эффективный метод Swap?

Скажем, для T[] и для List<T>. Как бы вы лучше всего реализовали метод, который меняет два элемента на эти два?

Swap(ref cards[i], ref cards[n]);   // How is Swap implemented?

Ответы [ 5 ]

25 голосов
/ 16 февраля 2009

Хорошо, код, который вы опубликовали (ref cards[n]), может работать только с массивом (не списком) - но вы должны использовать просто (где foo и bar - это два значения):

static void Swap(ref int foo, ref int bar) {
    int tmp = foo;
    foo = bar;
    bar = tmp;
}

Или, возможно (если вы хотите атомарный):

Interlocked.Exchange(ref foo, ref bar);

Лично я не думаю, что буду беспокоиться о методе подкачки, просто сделайте это напрямую; это означает, что вы можете использовать (для списка или для массива):

int tmp = cards[n];
cards[n] = cards[i];
cards[i] = tmp;

Если вы действительно хотите написать метод подкачки, работающий с списком или массива, вам нужно сделать что-то вроде:

static void Swap(IList<int> list, int indexA, int indexB)
{
    int tmp = list[indexA];
    list[indexA] = list[indexB];
    list[indexB] = tmp;
}

(было бы тривиально сделать это универсальным) - однако оригинальная «встроенная» версия (т.е. не метод), работающая с массивом, будет быстрее.

4 голосов
/ 04 января 2010

Использование:

void swap(int &a, int &b)
{
    // &a != &b
    // a == b OK
    a ^= b;
    b ^= a;
    a ^= b;
    return;
}

Я не понял, что я нахожусь в разделе C #. Это код C ++, но он должен иметь ту же основную идею. Я верю, что XOR тоже есть в C #. Похоже, вместо & вам может понадобиться "ref" (?). Я не уверен.

3 голосов
/ 20 декабря 2013

А как насчет этого? Это общая реализация метода подкачки. Jit создаст скомпилированную версию ТОЛЬКО для закрытых типов, так что вам не нужно беспокоиться о производительности!

/// <summary>
/// Swap two elements
/// Generic implementation by LMF
/// </summary>
public static void Swap<T>(ref T itemLeft, ref T itemRight) {
    T dummyItem = itemRight;
    itemLeft = itemRight;
    itemRight = dummyItem;
}

НТН Lorenzo

3 голосов
/ 16 февраля 2009

Хороший обмен - это тот, в котором вы не меняете содержимое. В C / C ++ это было бы похоже на обмен указателей вместо обмена содержимым. Этот стиль обмена быстрый и поставляется с некоторыми исключениями. К сожалению, мой C # слишком ржавый, чтобы я мог поместить его в код. Для простых типов данных этот стиль мало что дает. Но если вы привыкли и имеете дело с более крупными (и более сложными) объектами, это может спасти вам жизнь.

0 голосов
/ 20 января 2014

Для всех, кто интересуется, подкачка также может быть выполнена с помощью методов расширения (.NET 3.0 и новее).

В целом, кажется, нет возможности сказать, что в методах расширения это значение равно ref, поэтому вам нужно вернуть его и переопределить старое значение.

public static class GeneralExtensions {
    public static T SwapWith<T>(this T current, ref T other) {
        T tmpOther = other;
        other = current;
        return tmpOther;
    }
}

Этот метод расширения может быть использован следующим образом:

int val1 = 10;
int val2 = 20;    
val1 = val1.SwapWith(ref val2);
...