在Java中,如何使用已有的clear()
方法删除链表中的所有元素without?这个练习的灵感来自于电话采访中收到的一个问题。
说我可以用 C 来做这个
void DeleteAllElement( ListElement **head ) {
ListElement *deleteMe = *head;
while( deleteMe ) {
ListElement *next = deleteMe->next;
delete deleteMe;
deleteMe = next;
}
*head = NULL;
}
谢谢
Java有自动垃圾回收功能,所以你只需要将Head引用设置为null即可:
myList.headNode = null;
所以,假设我们有
LinkedList
类,它也有 resetList
函数...
public class LinkedList{
private Node head;
public Node find(Key k){ ... }
public void add(Node n){ ... }
...
public void reset(){ head = null;}
public static void reset(LinkedList l){l.reset();}
}
如果我们不将
head
节点设为私有,我们可以简单地执行我发布的第一个代码片段。
如果您正在谈论
java.util.LinkedList
的一个实例:
while (!linkedlist.isEmpty()) {
linkedlist.removeFirst();
}
如果您正在谈论任何
java.util.List
的实例:
while (!list.isEmpty()) {
list.remove(0);
}
请记住,
remove
是可选操作。然而,根据列表的实现,这可能会非常低效。对于 ArrayList
这会更好:
while (!list.isEmpty()) {
list.remove(list.size() - 1);
}
另一种选择是迭代列表并在每个元素上调用
Iterator.remove()
...也是一个可选操作。 (但是,对于某些列表实现来说,这可能会非常低效。)
如果您正在谈论自定义链表类,那么答案取决于您声明列表类内部数据结构的方式。
我怀疑,如果面试官提到
clear()
方法,他们期待的是标准 Java 集合框架上下文中的答案……而不是自定义链表类。
阅读实际代码很有用。建议你看看。
对于单链表,你可以像 @bdares 那样做,建议当你查看 java.util.LinkedList 的实际代码(这是大多数开发人员使用的)时,答案是相当不同的。
public void clear() {
Entry<E> e = header.next;
while (e != header) {
Entry<E> next = e.next;
e.next = e.previous = null;
e.element = null;
e = next;
}
header.next = header.previous = header;
size = 0;
modCount++;
}
首先要注意的是;这是用于向前和向后遍历的双向链表,它会主动清除所有引用。不知道为什么这样做是为了诚实,因为 GC 会以任何方式清除这些 eup,并且
modCount
会拾取另一个线程中的任何更改。事实上它应该首先执行 modCount。
为了比较,这里是 ArrayList.clear();
public void clear() {
modCount++;
// Let gc do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
for(i=0;i<linkedlist.size;i++){
linkedlist.removeFirst();
}
或参见此示例。
关于清除链表中节点之间的链接的几个要点:
世代垃圾收集:
某些垃圾收集器(包括分代垃圾收集器)在从所有引用中清除对象时工作效率更高。分代垃圾收集器根据对象的年龄将对象分为不同的代。
断开节点之间的所有链接有助于解决丢弃节点可能存在于不止一代的情况。通过断开所有连接,确保可以更有效地收集这些节点。
迭代器的可达性:
清除节点之间的链接可以确保即使有可达的Iterator或其他引用,通过链表结构节点本身也是不可达的。这保证了节点有资格进行垃圾收集。
在某些情况下,对象可能会通过迭代器或其他外部引用间接引用,并且破坏内部链接有助于确保节点不会由于此类外部引用而保留在内存中。
实际上,是否清除节点之间的所有链接取决于您的应用程序的具体要求和特点。如果您确信没有外部引用保留节点,则出于性能原因,您可以考虑省略此步骤。但是,如果您想确保即使在复杂的情况下也能回收内存,则清除所有链接可能是一种保守且安全的方法。因此,在我看来,如果您甚至有单链表,并且在任何文件中的任何位置的程序中(如果您有变量)存在直接或间接引用的 someRaddomVarible = head.next.next.next; 然后,即使你将头部和尾部清空, someRaddomVarible 也是可访问的并连接到链接(直接或间接),而这反过来 GC 也不会删除 RAM 中连接的(直接或间接)对象,所以我会考虑更好的 O(n) 时间任何类型的链表的复杂性。
单链表:
public void clear() {
// Disconnect all links between nodes
LinkedListNode current = head;
while (current != null) {
LinkedListNode next = current.next;
current.next = null;
current = next;
}
// Set head to null
head = null;
}
循环链表:
public void clear() {
if (head == null) {
return; // Empty list
}
// Disconnect all links between nodes
LinkedListNode current = head;
do {
LinkedListNode next = current.next;
current.next = null;
current = next;
} while (current != head);
// Set head to null
head = null;
}
双向链表:
public void clear() {
// Disconnect all links between nodes
LinkedListNode current = head;
while (current != null) {
LinkedListNode next = current.next;
// For doubly linked lists
current.prev = null;
current.next = null;
current = next;
}
// Set head and tail to null
head = null;
// For doubly linked lists
tail = null;
}
循环双向链表:
public void clear() {
// Disconnect all links between nodes
LinkedListNode current = head;
while (current != null) {
LinkedListNode next = current.next;
// For doubly linked lists
current.prev = null;
current.next = null;
current = next;
}
// Set head and tail to null
head = null;
// For doubly linked lists
tail = null;
}