我正在开发一个单链表,我想尝试另一种方法来实现我的删除函数算法:
template<class T>
inline void LinkedList<T>::remove(T v)
{
Node<T>** indirect = &head;
while (*indirect && (*indirect)->value != v) {
indirect = &((*indirect)->next);
}
*indirect = ((*indirect)->next);
}
通过new
创建我的所有节点。最后一行只是将指针更改为以下节点。但我应该释放*indirect
之前指向的记忆,对吧?
我更改了代码,以便释放底层节点指针的节点内存。我还跟踪前一个节点以保持尾指针:
template<class T>
inline void LinkedList<T>::remove(T v)
{
Node<T>** indirect = &head;
Node<T>* prev = nullptr;
while (*indirect && (*indirect)->value != v) {
prev = *indirect;
indirect = &((*indirect)->next);
}
if (*indirect) {
if (*indirect == tail) {
tail = prev;
}
Node<T>* tmp = *indirect;
*indirect = (*indirect)->next;
delete tmp;
}
}
答案 0 :(得分:1)
是,如果节点已分配new
,则应使用delete
删除该节点。
也就是说,您错过了节点删除,更重要的是在最终解除引用之前检查了null。你的实际枚举循环看起来很稳定(对此有所了解;指针指针对某些人来说并不容易掌握)。
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;
}
}
唯一剩下的就是在以下条件下验证上述机器。发生什么事......
每一个的答案都值得进行心理锻炼,可能还有一些纸,笔/铅笔,一些盒子和一些箭头。在每个条件中浏览上面的代码,看看会发生什么。如果一切看起来都是正确的,它可能是可靠的。当然,编写一堆单元测试来为上述每个条件制作列表并测试函数总是一个坚实的想法。
无论如何,那就是它。