Да, если узел был выделен с помощью new
, его следует удалить с помощью delete
.
Тем не менее, вы пропускаете удаление узла и, что более важно, проверку на нуль перед окончательным разыменованием. Ваш фактический цикл перечисления выглядит солидно (приятно; указатели на указатели не являются тривиальными для некоторых людей).
template<class T>
inline void LinkedList<T>::remove(T v)
{
Node<T>** indirect = &head;
while (*indirect && (*indirect)->value != v)
indirect = &((*indirect)->next);
if (*indirect)
{
Node<T> *tmp = *indirect;
*indirect = tmp->next;
delete tmp;
}
}
Предупреждение: убедитесь, что ваш деструктор Node
не делает глупостей, например, не пытается удалить связанную цепочку.
Управляемый список с указателями head
и tail
Если в вашем списке есть указатели head
и tail
для облегчения вставки O(1) на обоих концах, алгоритм будет немного сложнее, но сложность останется прежней. Вы должны поддерживать указатель prev
во время цикла перечисления, первоначально оцененный в nullptr
, и проходить его на один узел назад от основной итерации:
template<class T>
inline void LinkedList<T>::remove(T v)
{
Node<T>** indirect = &head, *prev = nullptr;
while (*indirect && (*indirect)->value != v)
{
prev = *indirect;
indirect = &((*indirect)->next);
}
if (*indirect)
{
Node<T> *tmp = *indirect;
// if the victim of the delete is also the tail
// then set it to the prior node pointer, which
// may be null if this was a single node list and
// both head and tail refer to the same node.
if (tail == tmp)
tail = prev;
*indirect = tmp->next;
delete tmp;
}
}
Осталось только проверить машину выше со следующими условиями. Что происходит, когда...
- В списке нет подходящих узлов?
- В списке есть один узел, который соответствует?
- Есть несколько узлов, и первый узел совпадает?
- Есть несколько узлов, и последний узел совпадает?
- Есть несколько узлов, и какой-то средний узел совпадает?
Ответы на каждый из них стоят умственного упражнения и, возможно, бумаги, ручки/карандаша, нескольких коробок и нескольких стрелок. Пройдитесь по приведенному выше коду в каждом условии и посмотрите, что произойдет. Если все кажется правильным, это, вероятно, прочно. Конечно, написание стека модульных тестов, формирующих списки для каждого из приведенных выше условий, и тестирование функции — это всегда хорошая идея.
Во всяком случае, это все.
person
WhozCraig
schedule
26.02.2017
new
должен бытьdelete
. На каждыеnew Type[n]
должно бытьdelete[]
. И как только вы освоите это, позвольте умным указателям делать всю работу за вас и ежедневно старайтесь никогда не заниматься управлением памятью вручную. Тем не менее, вам не хватаетdelete
, и вам не хватает проверки на нуль перед окончательным косвенным обращением (случай, когда цикл исчерпан, и вы никогда не найдете значение). - person WhozCraig   schedule 26.02.2017