Есть ли в c#/.net x.x реализация двусвязного списка (который можно повторять в обратном порядке)?

Я искал стандартную реализацию двусвязного списка в С# (так что у меня есть связанный список, который я могу перебирать назад) и не могу его найти. Я чувствую, что что-то настолько простое должно иметь реализацию, которую мне просто не хватает.

Если он существует, для какой версии c#/.net он существует?

Обратная итерация в целом кажется чем-то, что не предназначено для С#. Я просто слишком сильно застрял в режиме С++/stl или этого очень не хватает в С#?

Я знаю о LinkedList, но, не найдя способа перебрать его в обратном направлении, предположил, что он односвязный.

Если LinkedList дважды связан, как можно перебирать его в обратном направлении (эффективно)?


person Catskul    schedule 26.01.2010    source источник


Ответы (4)


Помимо приведенных здесь ответов, вы можете написать метод расширения для LinkedList<T>, чтобы упростить его повторное использование:

public static IEnumerable<T> Backwards<T>(this LinkedList<T> list)
{
    LinkedListNode<T> node= list.Last;
    while (node != null)
    {
        yield return node.Value;
        node = node.Previous;
    }
}

Использовать с:

foreach (string x in list.Backwards())
{
    // ...
}
person Jon Skeet    schedule 26.01.2010
comment
Спасибо. Я немного смущен, почему что-то подобное уже не входит в стандартную библиотеку. - person Catskul; 26.01.2010
comment
@Catskul вот хорошая ссылка, которая объясняет, что блоги .msdn.com/ericlippert/archive/2009/05/18/. - person Matt Warren; 26.01.2010
comment
@ Мэтт: Спасибо. ИМХО, итерация в обратном направлении по списку является более базовой функциональностью, чем обсуждаемый там ForEach (например, итерация в обратном направлении обеспечивается большинством контейнеров STL), и, поскольку ее там нет, похоже, что создатели С# предлагали вам не не делать это. В C#, даже когда я знаю, как что-то сделать, реализовав это самостоятельно, мне кажется, что если я не нашел простого способа, значит, я что-то упустил/делаю что-то не так. - person Catskul; 26.01.2010

Следующий код будет эффективно перебирать LinkedList в обратном порядке:

        LinkedList<string> list = new LinkedList<string>
            (new[] {"cat", "dog", "frog", "antelope", "gazelle"});
        LinkedListNode<string> item = list.Last;
        do
        {
            Console.WriteLine(item.Value);
            item = item.Previous;
        }
        while (item != null);
        Console.ReadKey();

Ключевым моментом здесь является то, что LinkedList содержит ссылку только на экземпляры First и Last LinkedListNode списка. Каждый экземпляр LinkedListNode содержит ссылку на следующий и предыдущий элемент в списке (или null на каждом конце списка), а также свойство Value. Это означает, что итерация от первого или последнего узла LinkedListNode проста, но произвольный доступ требует итерации от первого или последнего узла в списке.

Если вам нужно сделать вставку по пути, используйте LinkedList.AddBefore или AddAfter, чтобы вставить новый LinkedListNode.

person spender    schedule 26.01.2010
comment
Это то, что я искал. По какой-то причине у меня сложилось впечатление, что List‹T›.Last вернет что-то типа T. Спасибо. Каким-то образом вы единственный человек, который, кажется, вообще понял проблему или даже концепции связанных списков: / - person Catskul; 26.01.2010
comment
Сильно недооцененный контейнер. Рад помочь. - person spender; 26.01.2010
comment
Это вызовет исключение ArgumentNullException, если список пуст. Изменение цикла do/while на (более простой для чтения, IMO) цикл while решит проблему - см. мой ответ для примера. - person Jon Skeet; 26.01.2010
comment
Да, я видел это и просто преобразовал цикл while в своей голове, не задумываясь о последствиях do/while. - person Catskul; 26.01.2010

Как насчет System.Collections.Generic.LinkedList()

Вот документы на MSDN:

http://msdn.microsoft.com/en-us/library/he2s3bh7.aspx

Информация о версии
.NET Framework: поддерживается в версиях: 3.5, 3.0, 2.0
.NET Compact Framework: поддерживается в версиях: 3.5, 2.0
XNA Framework: поддерживается в версиях: 3.0, 2.0 , 1,0

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

person JohnFx    schedule 26.01.2010
comment
У меня есть особая потребность иметь возможность перебирать список в обратном порядке и иметь дешевые вставки + дешевое изменение порядка. - person Catskul; 26.01.2010
comment
Хорошо, тогда первая часть моего ответа должна вам помочь. - person JohnFx; 26.01.2010
comment
RTFM бесполезен, особенно потому, что в документах конкретно не рассматривается обратная итерация. Если мы просто собираемся рассказать всем RTFM, то зачем вообще Stackoverflow? - person Catskul; 26.01.2010
comment
Это вряд ли RTFM. Вы просили .net-реализацию двусвязных списков, и я дал вам имя соответствующего объекта фреймворка, ответил на ваш вопрос о том, какие версии фреймворка его поддерживают, и дал вам ссылку на документацию по нему. Вы никогда не просили код для отображения обратной итерации, вы просто размышляли о том, предназначено ли это для этого. Единственный вопрос, на который я не ответил, это «Моя голова просто застряла»… который я воспринял как риторический. - person JohnFx; 26.01.2010
comment
Извините, я неправильно вас истолковал. Ответ Хорошо, тогда первая часть моего ответа должна вам помочь Ответ на мою итерацию показался мне RTFM. - person Catskul; 26.01.2010

Как насчет LinkedList?

person kenny    schedule 26.01.2010
comment
Как вы эффективно перебираете его в обратном порядке? - person Catskul; 26.01.2010
comment
в то время как (nodeP != null) nodeP = nodeP.Previous; - person kenny; 26.01.2010