Добавление значения в односвязный список

0

Я в классе структур данных C++, и недавнее задание на домашнюю работу прослушивало меня в течение нескольких дней. Он должен работать с односвязными списками, и один из методов, который мы должны писать, связан с добавлением значений в список.

Во-первых, мы создаем head фиктивного узла:

template<typename T>
SLList<T>::SLList()
{
  head = new Node; // Node() is ok too
}

Если я прав, это не должно иметь значения, не так ли? Поэтому голова должна быть NULL. Это то, что мне удалось создать (с моей помощью профессора).

template<typename T>
void SLList<T>::add(const T& val) {
    bool duplicate = false;
    //Node *ptr = head->next;
    //cout << head->data;

    for (Node *ptr = head->next; ptr != NULL; ptr = ptr->next) {
    //while (ptr == NULL) {
        //ptr = ptr->next;
        // if ptr is initialized as head, the first node, then ptr != NULL
        // if ptr is initialized as head->next, which it should in order to
        // traverse from the node AFTER the head, then ptr == NULL
        // not exactly sure why.
        if (ptr->data == val) {
            duplicate = true;
            break;
        }
    }
    //Node *temp = new Node(val); // create new node with new element.
    //temp->next = ptr->next;
    //ptr->next = temp;

    if (duplicate) {
        cout << "Duplicate entry found: " << val << endl;
    }
}

Я пробовал работать с for и в while циклы, так как много результатов Google использовал в while циклы в своих ответах. То, что я пытаюсь сделать, это попытаться добавить значение в список. Если значение уже находится в этом списке, оно не добавляется. Я пытаюсь сделать это с помощью:

SLList<int> iList;
iList.add(5);
iList.add(6);
iList.add(6);

Когда я попросил о помощи, мне сказали, что я должен инициализировать *ptr как head->next чтобы начать перемещение списка для узла ПОСЛЕ фиктивного узла. Я использовал отладчик Visual Studio и обнаружил, что после инициализации его head->next программа никогда не head->next в цикл for, который, как я предполагаю, head->next тем, что узел после фиктивного узла выходит из строя с помощью инструкции if ptr != NULL. Я не совсем уверен, почему это так, как если бы у меня был Node *ptr = head он бы прошел через список просто отлично (хотя следующая строка, if (ptr->data == val), рассмотрит каждую запись как двойную запись).

Возможно, я понимаю это неправильно, но не должен ли head узел иметь значение NULL? Поэтому он не должен передавать оператор if в цикле for.

Также существует проблема с тремя строками после цикла for, поскольку, когда программа там опускается, она просто падает и не добавляет никаких значений в список, но я решил, что просто сделаю это на один шаг время.

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

  • 0
    head конечно, не должна быть NULL. Оператор new не возвращает нулевые указатели. Просто значения данных не будут содержать хороших данных, поскольку это просто фиктивный узел.
  • 0
    @ooga О, я вижу .. Так что есть данные, но не хорошие данные? Я просто подумал, что NULL будет таким же, как 0 .
Показать ещё 1 комментарий
Теги:
linked-list

4 ответа

1

Ваш главный недостаток дизайна здесь выглядит следующим образом: вы переходите к концу своего списка и берете его оттуда, но конец имеет значение null, поэтому вам нужно вернуться назад, чтобы найти что-то, что не является нулевым. Например (основной пример)

Node<T>* last = head;
for(Node<T>* ptr = head->next; ptr != NULL ; ptr = ptr->next){
    last = ptr;
    //do something
}

Поэтому, когда цикл закончен, вы знаете, что если ptr==NULL то last - это хвост вашего списка, и все, что вы хотите добавить, должно следовать за ним.

Это также проблема в трех строках кода после цикла for: если я правильно вас понимаю, в случае, если нет дубликата, вы выполняете итерацию до тех пор, пока ptr будет NULL. Поэтому при выходе из ptr->next произойдет сбой. Это означает, что при добавлении элемента, если этот элемент отсутствует в списке, ваша функция не работает (по дизайну, а не случайно).

  • 0
    Таким образом, вместо того, чтобы позволить head просто плавать вокруг, мы назначаем ее на last и проходим цикл, верно? Затем, если ptr != NULL он войдет в цикл for и назначит ptr для last и просто постоянно обновляет его до ptr == NULL ? Тогда если так (объединяя это с ответом ooga ниже), предполагая, что нет дубликата, prev->next (который, я считаю, действительно будет ptr->next , создаст новый узел со значением? Есть вероятность, что я слишком усложняю это хотя.
  • 0
    Ну, ответ Ооги на самом деле просто полное решение. Я дал вам только частичное решение, потому что я объяснял концепцию. Но это prev-> next (в моем решении last-> next), потому что ptr всегда на шаг впереди последнего (prev в решении ooga), поэтому, если ptr находится на один конец в конце списка, last (или prev) будет последний узел В случае, если узел является только головой, он пропустит цикл for и добавит новый узел (в решении ooga, то есть мой комментарий в основном пояснительный)
1

Попробуйте что-то вроде этого:

template<typename T>
void SLList<T>::add(const T& val) {
    Node<T>* prev = head;
    for (Node<T>* ptr = head->next; ptr; ptr = ptr->next) {
        if (ptr->data == val) {
            std::cout << "Duplicate: " << val << '\n';
            return;
        }
        prev = ptr;
    }
    prev->next = new Node<T>(val);
}
  • 0
    Я комбинирую это с ответом Elayeek выше, так что я предполагаю, что мы проверяем, есть ли значение ptr в цикле foor. Если это так, мы запускаем проверку дубликатов, тогда prev становится тем, что есть ptr , так что head = ptr ?
0

У вас здесь пара вариантов. Наиболее распространенным является то, что вы установили head указатель на nullptr, пока вы не добавить узел. В этом случае у вас просто не было (или нужно) фиктивного узла вообще.

Другая возможность - создать список, изначально содержащий фиктивный узел. Это может немного упростить остальную часть кода, поскольку это позволяет избежать наличия специального кода случая для добавления первого узла в пустой список. Вы также можете использовать фиктивный узел как "дозорный", содержащий некоторый элемент данных, который не разрешен во всей остальной части списка. При правильных обстоятельствах это может упростить прохождение списка, позволяя вам просматривать только содержащиеся данные, а не проверять нулевой указатель, сигнализирующий о конце списка. Первым примером является список чисел с плавающей запятой, которые вы сохраняете в отсортированном порядке, с фиктивным узлом, содержащим infinity. В этом случае найти число можно упростить из:

while (ptr != nullptr && ptr->data < search_item) {
    // ...
    ptr=ptr->next;
}

...чтобы просто:

while (ptr->data < search_item) {
    // ...
    ptr = ptr->next;
}

infinity в конце списка гарантирует, что если ничего больше в списке больше, чем search_item, фиктивный узел будет (хотя для этого явно требуется, чтобы вы не вставляли элемент в список с infinity качестве его значения).

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

0

ГЛАВА

Когда список пуст, голова должна быть NULL. Это происходит при создании или после добавления и удаления равного количества узлов. Во всех других ситуациях голова должна быть не-NULL, и она должна указывать на первый добавленный узел.

ADD (типичный)

Node * ptr = new Node;
ptr->next = head;
head = ptr;

ADD (только не дубликат)

bool const exists = std::find( list, element );
if( ! exists ) {
    Node * ptr = new Node;
    ptr->next = head;
    head = ptr;
}
  • 0
    Вы, очевидно, не читали вопрос, поскольку он указывает, что head - это фиктивный узел, который, конечно, не может быть нулевым.
  • 0
    У меня проблемы с пониманием того, что делает код. Не могли бы вы объяснить? А также, что касается проверки, является ли список пустым, будет if (iList == NULL) { add head to iList) что-то вроде if (iList == NULL) { add head to iList) ?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню