Есть ли что-либо волшебное о ReadOnlyCollection

Да, там "следующая перестановка" алгоритм, и это довольно просто также. Стандартная библиотека шаблонов (STL) C++ даже имеет функцию, вызванную next_permutation.

алгоритм на самом деле находит следующий перестановка - лексикографически следующая. Идея - это: предположите, что Вам дают последовательность, говорите "32541". Какова следующая перестановка?

, Если Вы думаете об этом, Вы будете видеть, что это "34125". И Ваши мысли были, вероятно, чем-то это: В "32 541",

  • нет никакого способа сохранить эти "32" зафиксированных и найти более позднюю перестановку в "541" часть, потому что та перестановка уже является последней для 5,4, и 1 - это отсортировано в порядке убывания.
  • , Таким образом, необходимо будет измениться "2" на что-то большее - на самом деле, на самое маленькое количество, больше, чем он в "541" часть, а именно, 4.
  • Теперь, как только Вы решили, что перестановка запустится как "34", остальная часть чисел должна быть в увеличивающемся порядке, таким образом, ответ "34125".

алгоритм должен реализовать точно что цепь рассуждений:

  1. Находят самый длинный "хвост", который заказан в порядке убывания. ("541" часть.)
  2. Изменение число незадолго до хвоста ("2") к самому маленькому количеству, больше, чем он в хвосте (4).
  3. Сортируют хвост в увеличивающемся порядке.

можно сделать (1). эффективно путем запуска в конце и движения назад, пока предыдущий элемент не меньше, чем элемент тока. Можно сделать (2). просто подкачав "4" с '2", таким образом, Вы будете иметь "34521". Как только Вы делаете это, можно избегать использования алгоритма сортировки для (3)., потому что хвост был и все еще (думайте об этом), отсортированный в порядке убывания, таким образом, он только должен быть инвертирован.

код C++ делает точно это (посмотрите на источник в /usr/include/c++/4.0.0/bits/stl_algo.h в Вашей системе или посмотрите эта статья ); должно быть просто перевести его в Ваш язык: [Считайте "BidirectionalIterator" как "указатель", если Вы незнакомы с итераторами C++. Возвраты кода false, если существует никакая следующая перестановка, т.е. мы уже в порядке убывания.]

template 
bool next_permutation(BidirectionalIterator first,
                      BidirectionalIterator last) {
    if (first == last) return false;
    BidirectionalIterator i = first;
    ++i;
    if (i == last) return false;
    i = last;
    --i;
    for(;;) {
        BidirectionalIterator ii = i--;
        if (*i <*ii) {
            BidirectionalIterator j = last;
            while (!(*i <*--j));
            iter_swap(i, j);
            reverse(ii, last);
            return true;
        }
        if (i == first) {
            reverse(first, last);
            return false;
        }
    }
}

могло бы казаться, что это может взять O (n) время на перестановку, но если Вы думаете об этом более тщательно, можно доказать, что это берет O (n!) время для всех перестановок всего, поэтому только O (1) - постоянное время - на перестановку.

хорошая вещь состоит в том, что алгоритм работает, даже когда у Вас есть последовательность с повторными элементами: с, скажем, "232254421", это нашло бы хвост как "54 421", подкачало бы "2" и "4" (так "232454221"), инвертировало бы остальных, дав "232412245", который является следующей перестановкой.

11
задан Jon Seigel 20 April 2010 в 15:39
поделиться

3 ответа

Самое питоническое решение - задокументировать примеры. Если возможно, укажите, какие операции объект должен поддерживать, чтобы быть приемлемым, а не конкретный тип.

class Host(object):
  def __init__(self, name, network_interface)
    """Initialise host with given name and network_interface.

    network_interface -- must support the same operations as NetworkInterface

    >>> network_interface = NetworkInterface()
    >>> host = Host("my_host", network_interface)

    """
    ...

На этом этапе подключите ваш источник к doctest , чтобы убедиться, что ваши примеры документов продолжают работать в будущем. .

Это сделано намеренно и полезно - это означает, что, когда компилятор знает , что это ReadOnlyCollection , неподдерживаемые функциональные возможности недоступны для вас, что помогает отвлечь вас из-за сбоя во время выполнения.

Это интересный и относительно необычный шаг, эффективно реализует половину свойства / индексатора неявно, а половину явно.

В отличие от моих предыдущих мыслей, я считаю ReadOnlyCollection на самом деле явно реализует весь индексатор, но также предоставляет общедоступный индексатор только для чтения. Другими словами, это примерно так:

T IList<T>.this[int index]
{
    // Delegate interface implementation to "normal" implementation
    get { return this[index]; }
    set { throw new NotSupportedException("Collection is read-only."); }
}

public T this[int index]
{
    get { return ...; }
}
16
ответ дан 3 December 2019 в 06:22
поделиться

Никакого волшебства, ReadOnlyCollection просто имеют разные реализации для собственного индексатора и индексатора, реализующего интерфейс IList :

public T Item[int index] { get; }

T IList<T>.Item[int index] { get; set; }

Если вы приведете свой список к IList , вы получите ошибку времени выполнения вместо ошибки компиляции:

((IList<int>)b)[2] = 3;

Изменить:
Чтобы реализовать индексатор в вашем собственном классе, вы используете ключевое слово this :

public T this[int index] { get { ... } }

T IList<T>.this[int index] { get { ... } set { ... } }
1
ответ дан 3 December 2019 в 06:22
поделиться

Он явно реализует IList.Items, что делает его закрытым, и вам придется преобразовать его в интерфейс, чтобы достичь его реализации, и реализует новый индексатор this [...] , который используется вместо него, у которого есть только get-accessor.

Если вы приведете коллекцию к IList, ваш код будет компилироваться, но вместо этого завершится с ошибкой во время выполнения.

К сожалению, я не знаю, как это сделать в C #, поскольку написание индексатора на C # включает использование ключевого слова this , и вы не можете написать это:

T IList<T>.this[int index] { get; set; }
2
ответ дан 3 December 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: