今天在刷力扣的时候因为一道比较简单的题卡住了,题目如下
比较常规的写出了一开始的代码。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> q=new LinkedList<>();
List<Integer> curLevel=new LinkedList<>();
List<List<Integer>> res=new LinkedList<>();
q.offer(root);
int n=1;
int nums=1;
while(q.peek()!=null){
TreeNode curNode=q.poll();
nums--;
curLevel.add(curNode.val);
if(curNode.left!=null){q.offer(curNode.left);nums++;}
if(curNode.right!=null){q.offer(curNode.right);nums++;}
if(--n==0){
res.add(curLevel);
n=nums;
curLevel.clear();
}
}
return res;
}
}
但是运行的时候发现,结果是这样的
经过调试,发现问题在curLevel.clear()上,当修改后
改为
curLevel=new LinkedList<Integer>()
发现就对了。
因为之前刷题的话C++写的比较多,所以习惯性的用clear()方法,今天就遇到了问题,然后开始发现了问题。
很显然的是,clear()方法一定不是简单的把这个List的内容或首地址清空,一定程度上涉及了指针操作,猜想是由于clear把里面的元素的引用给释放了。
带着猜想去读了下源码。
首先是ArrayList的clear源码
/**
* Removes all of the elements from this list. The list will
* be empty after this call returns.
*/
public void clear() {
modCount++;
// Let gc do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
然后是LinkedList的clear源码
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
看代码不难发现,clear()方法把List内每个元素的引用全部置为null,由于Java的自动GC机制,其引用对应的内存因为没有引用都被回收,所以我最后返回res的时候,因为引用的内容被清空了,所以我访问到的三个List都是空的List。
错误的原因找到了,然后查看利用重新初始化的方法。
原因也比较显然,重新初始化的时候重新创建了空间,引用被赋值了,而原先List内部的元素引用都仍然在,仍可以通过原先的引用访问到元素的内容。
所以,还是要多读源码....