如何“完全”删除链表中的所有节点?
Posted
技术标签:
【中文标题】如何“完全”删除链表中的所有节点?【英文标题】:How to "completely" delete all nodes in a linked list? 【发布时间】:2016-03-19 01:22:34 【问题描述】:我很好奇指针和删除指针在 C++ 中是如何工作的,所以我做了一个实验。我制作了一个非常简单的单链表和以下递归函数,用于删除列表中的所有节点:
void deleteList(Node *node)
if (!node)
return;
deleteList(node->next);
cout << "deleting node " << node->data << endl;
delete node;
node = nullptr;
我想这会成功删除列表中的所有节点。但是,在main中调用了这个函数后,我检查了头节点是否仍然存在:
List list;
// appending a bunch of numbers to the list...
list.deleteList(list.head);
if (list.head)
cout << true;
这将在控制台打印 1,这意味着头部确实仍然存在。我希望头部和它之后的所有其他节点都为空,因此 if 条件失败,因为将指针设置为空是我在递归函数中做的最后一件事。那么为什么程序会报告头部仍然存在呢?
编辑:更改列表列表();列出列表;
【问题讨论】:
List list();
不是你想的那样。 Most Vexing Parse
是的,我的实验中实际上有两个构造函数。上面示例中的一个调用另一个构造函数,该构造函数初始化诸如 0 的大小值和一个新的空头节点。
该语句根本不调用构造函数。它是一个函数list
的声明,它的返回类型是List
。对于对象初始化,()
需要被移除。
哦,你说得对。一时间不知道我在想什么
【参考方案1】:
您释放了内存,但分配给nullptr
只影响传递给函数的指针的副本,而不影响调用者中的原始指针。
如果你将函数声明为通过引用接收指针:
void deleteList(Node *&node)
那么node = nullptr;
的分配也会影响调用者。
请注意,由于您标记了此 C++11,因此将链表定义为正向的一系列 std::unique_ptr<Node>
s 通常要简单得多(如果它是双向的,则反向的原始指针避免引用循环),因此您可以避免需要特殊的删除函数,只需将头指针设置为nullptr
,让C++完成级联删除的工作。
编辑:让std::unique_ptr
完成工作是有缺陷的;正如在 cmets 中所指出的,这意味着列表大小实际上受到堆栈的限制,并且当您删除它们时,太大的列表会导致堆栈溢出。因此,明确地一一清除(最简单的方法是正确实现弹出,并且清除只是弹出直到 head
通过 popleft
方法转换为 nullptr
)会更安全。我将最初的建议留给后人,所以这个解释是有道理的。
【讨论】:
完美,感谢您的澄清。我认为指针总是通过引用传递。这是我第一次听说唯一指针(如果这就是它们的名称?)。我需要更多地了解这些 @MannyKim:是的,unique pointers。指针很有趣,因为指针本身是按值传递的;两个指针最初都引用相同的内存,但是更改被调用者中的指针不会影响调用者,它只会更改指向的数据(包括在该位置释放内存的效果;不要取消引用你知道的指针由另一个函数释放)可见。 为了清楚起见,“释放指针”是指“删除节点”,“取消引用指针”是指“节点 = nullptr”,对吗?并感谢您提供的额外细节,它确实使指针更容易理解 @MannyKim:“释放”和“删除”是等价的;在 C 中,您使用free
函数,在 C++ 中,您使用 delete
关键字(尽管理想情况下,您使用像 unique_ptr
和 shared_ptr
这样的智能指针以避免需要显式使用 delete
)。取消引用指针意味着实际使用它来查找数据,使用*
或->
。删除实际上也有效地取消了指针的引用(删除它两次是一个严重的错误)。分配nullptr
既不删除/释放也不引用哑指针,但对于唯一指针,它相当于一次删除和清除指针。
让C++做递归数据结构的级联删除工作会导致栈溢出。以上是关于如何“完全”删除链表中的所有节点?的主要内容,如果未能解决你的问题,请参考以下文章
Leetcode练习(python):链表类:第82题:删除排序链表中的重复元素 II:给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。