我有简单的代码,可以打印树中特定节点的路径。我使用java String的实现如下
//using strings
public static void getPathS(Node node,String path,int key){
if (node == null) {
return;
} else if(node.data == key) {
System.out.println(path+" "+key);;
}
getPathS(node.left,path+" "+node.data,key);
getPathS(node.right,path+" "+node.data,key);
}
假设下面有树,
如果我在3上调用getPathS,则上面的实现将打印
1 34 3 //path from root to the element
如果我使用ArrayList实现相同的方法,如下所示
public static List getPath(Node node, List<Integer> path, int key) {
if (node == null) {
//1 . path = new ArrayList<Integer>();
path = new ArrayList<Integer>();
// 2. or tried path.clear() -- it should clear the path
//return path;
return null;
} else if (node.data == key) {
path.add(node.data);
return path;
}
path.add(node.data);
return nonNull(getPath(node.left, path, key), getPath(node.right, path, key));
}
private List nonNull(List path1, List path2) {
if (path1 != null)
return path1;
if(path2 !=null )
return path2;
return null;
}
// class Node { Node left, Node right , int data; };
//Code to call getPath
Node node = new Node(1);
node.left = new Node(2);
node.left.left = new Node(4);
node.right = new Node(34);
node.right.right = new Node(3);
System.out.println(getPath(node, new ArrayList(), 3));
在第二个实现中,我尝试了两种方法,当我们得到NULL节点时,如果我为路径分配新的ArrayList
,则在第一种方法中,它会打印所有元素,即
[1, 2, 4, 34, 3]
如果我使用path.clear()
,它只打印最后一个元素,即要搜索的元素。
我们怎样才能确保ArrayList
在递归中作为String工作?
答案 0 :(得分:2)
这里的问题是,在调用nonNull()
时,您不会考虑两个分支机构的失败。
这是一个考虑到这种可能性的修正,如果我们未能在其子代中找到密钥,则删除当前节点的数据。
public static List<Integer> getPath(Node node, List<Integer> path, int key) {
if (node == null) {
return null;
} else if (node.data == key) {
path.add(node.data);
return path;
}
path.add(node.data);
// path is unchanged if nothing is found in left children
if (getPath(node.left, path, key) != null || getPath(node.right, path, key) != null) {
// found in one branch or the other
return path;
}
// not found in either branch, remove our data
path.remove(path.size() - 1);
return null;
}
当然,看起来我们正在操纵不同的列表,但只有一个:第一次作为参数提供的列表。这就是应该从中删除数据的原因。你需要清楚你的论点。
更清洁的解决方案,强调只有一个列表的事实。
/**
* Appends to the specified list all keys from {@code node} to the {@link Node} containing the
* specified {@code key}. If the key is not found in the specified node's children, the list is
* guaranteed to be unchanged. If the key is found among the children, then the specified list
* will contain the new elements (in addition to the old ones).
*
* @param node
* the node to start at
* @param path
* the current path to append data to
* @param key
* the key to stop at
* @return true if the key was found among the specified node's children, false otherwise
*/
public static boolean getPath(Node node, List<Integer> path, int key) {
if (node == null) {
// leaf reached, and the key was not found
return false;
}
// add data to the path
path.add(node.data);
// the OR is lazy here, so we treat everything in the given order
// if getPath failed on the left children, path is unchanged and used for right children
if (node.data == key || getPath(node.left, path, key) || getPath(node.right, path, key)) {
// the key is found in the current node, its left children, or its right children
return true;
}
// not found in either branch, remove our data
path.remove(path.size() - 1);
return false;
}
请注意,我没有使用path.remove(node.data)
,因为可能会有更多的节点包含该数据,而第一个节点将被移除而不是最后一个节点。