дважды связанный список в c#

#c# #list #linked-list

#c# #Список #связанный список

Вопрос:

Я использую дважды циклический связанный список. После добавления значений я извлекаю значения из списка. Я использую этот код для добавления значений:

 public void Add(T data)
{
    if (root == null)
    {
        this.Add(data);
        root = new LinkedListNode<T>(data);
        last = root;
    }
    else
    {
        last.Next = new LinkedListNode<T>(data);
        last.Next.Previous = last;
        last = last.Next;
    }
}
  

Я предоставляю данные в виде:

 char[] dir = { 'n', 'w', 's', 'e' };
TestProject.classes.LinkedList<char> list = new TestProject.classes.LinkedList<char>();

foreach (char c in dir)
{
    list.Add(c);
}
  

Я извлекаю данные списка как:

 public LinkedListNode<T> GetAt(int index)
{
    var current = root;
    for (int i = 0; i < index; i  )
    {
        if (current == null)
            return null;
        current = current.Next;
    }
    return current;
}
  

Проблема в том, что он выдает значение current as null при извлечении значения узла.

Список является примером из самого stackoverflow.

Пожалуйста, помогите мне..

Весь мой класс связанного списка выглядит как:

 public class LinkedList<T>
{
    protected LinkedListNode<T> root = null;
    protected LinkedListNode<T> last = null;
    public LinkedList()
    {
    }

    public string ToString()
    {
        StringBuilder sb = new StringBuilder();
        var node = root;
        while (node != null)
        {
            sb.Append("{ "   node.Data.ToString()   " } ");
            node = node.Next;
        }
        return sb.ToString();
    }

    public T this[int index]
    {
        get
        {
            var node = GetAt(index);
            if (node == null)
                throw new ArgumentOutOfRangeException();
            return node.Data;
        }
        set
        {
            var node = GetAt(index);
            if (node == null)
                throw new ArgumentOutOfRangeException();
            node.Data = value;
        }
    }

    public LinkedListNode<T> GetAt(int index)
    {
        var current = root;
        for (int i = 0; i < index; i  )
        {
            if (current == null)
                return null;
            current = current.Next;
        }
        return current;
    }

    public void Add(T data)
    {
        if (root == null)
        {
            this.Add(data);
            root = new LinkedListNode<T>(data);
            last = root;
        }
        else
        {
            last.Next = new LinkedListNode<T>(data);
            last.Next.Previous = last;
            last = last.Next;
        }
    }
}

public class LinkedListNode<T>
{
    public T Data { get; set; }

    public LinkedListNode(T data)
    {
        Data = data;
    }

    public LinkedListNode<T> Next { get; set; }
    public LinkedListNode<T> Previous { get; set; }
}
  

Комментарии:

1. Не является ли это: public void Add(T data) { if (root == null) { this.Add(data); тем самым рекурсивным (т. е. переполнением стека)? Вы многократно вызываете одну и ту же функцию снова и снова … нет причин, по которым root менялся между вызовами…

2. @forsvarir: но значение меняется, когда я повторно получаю данные из «public LinkedListNode<T> getAt(int index)» function..it присваивает значение current равному null..

3. @kawade вы инициализируете root в своем конструкторе? Вы устанавливаете last одинаковое значение?

4. @forsvarir: нет, я ничего не инициализирую в cunstructor

5. Можете ли вы опубликовать остальную часть класса list?

Ответ №1:

Если root == null при вызове этой функции нет причин для работы этой функции, это должно вызывать переполнение стека, когда она вызывает себя снова и снова…

 public void Add(T data)
{
    if (root == null)
    {
        this.Add(data);  // recurse?!?
  

Итак, если вы успешно вызываете его, кажется, есть три варианта:

  • Вам удалось настроить оптимизацию вашего компилятора таким образом, чтобы он удалял вызов (это кажется маловероятным, но я предполагаю, что это возможно).
  • Вы никогда не будете вызывать его с помощью root==null , что означает, что что-то еще изменяется root , возможно, поскольку оно защищено, однако, если предоставленный вами код использования верен, этого не должно быть, поскольку вы не упоминаете производный класс.
  • Ваш код использования перефразирован, и на самом деле вы вызываете add из блока try / catch и игнорируете генерируемое исключение.

Как я уже говорил в своем комментарии, удаление дополнительного вызова this.add(data) должно решить вашу проблему (с заполнением списка), однако я бы посоветовал вам пошагово выполнить вызовы функций в отладчике, чтобы вы могли видеть, что происходит. Мне было бы интересно узнать, действительно ли он вызывает функцию ‘Add’.

Что касается извлечения информации из списка, функция get выглядит так, как будто она должна работать, при условии, что информация была помещена в список правильно, и вы вызываете get в том же списке, в который были вставлены данные. Опять же, если это не работает, отладчик — ваш друг при попытке выяснить, какой бит заполнен не так, как вы ожидаете.

Ответ №2:

Как указано @forsvarir: вы не должны вызывать Add повторно, когда корневой узел не существует. Просто удалите этот вызов, и все будет в порядке.

На вашем месте я бы не добавлял индексатор или GetAt метод в LinkedList реализацию. Довольно неэффективно использовать связанный список, если вам нужен доступ к индексу.

Вместо этого сделайте свой список implementable IEnumerable и позвольте пользователям использовать LINQ.