我有几个清单:
A = ["a0", "a1"] // the number of lists varies
B = ["b0", "b1", "b2"] // such as the number of elements in a list.
C = ["c1"]
D = ["d0", "d1"]
我将此结构转换为树:
_____ROOT______
/ \
___a0____ ____a1____
/ | \ / | \
b0 b1 b2 b0 b1 b2
| | | | | |
c1 c1 c1 c1 c1 c1
/ | / | / | / | / | / |
d0 d1 d0 d1 d0 d1 d0 d1 d0 d1 d0 d1
我正在打印树中的每个唯一路径(省略根):
a0 -> b0 -> c1 -> d0
a0 -> b0 -> c1 -> d1
a0 -> b1 -> c1 -> d0
...
a1 -> b2 -> c1 -> d1
我是通过以下列方式遍历它来“摧毁”树本身来做到这一点:
public static void delete(Node node) {
if (node.isLeaf() && !node.isRoot()) {
Node parent = node.getParent();
parent.removeChild(node);
delete(parent);
}
}
public static void traverse(Node node) {
if (node.isRoot())
System.out.println("---");
else
System.out.println(node.getName());
if (node.isLeaf()) { // I'm still working on
if (!node.isRoot()) { // removing unnecessary checks
delete(node);
traverse(node.getRoot());
}
} else {
Node child = node.firstChild();
if (null != child)
traverse(child);
}
}
traverse(Node)
始终打印树的第一个可用路径(从根到叶),而delete(Node)
会剪切traverse(Node)
已访问过的树的叶子。
这可以按预期工作,但我很想找到一种解决方案,以前面描述的方式遍历树而不会破坏它。 如果有办法做到这一点,那么我有兴趣遍历这个相同的结构,但是以图形的形式来减少冗余。
答案 0 :(得分:10)
行。我认为你的意思是你想要找到从根到叶子的每条路径。
然后(未优化的版本)
void traverse (Node root) {
// assume root != NULL
traverse (root, new LinkedList<Node>());
}
private void traverse (Node root, LinkedList<Node> path) {
path.add(root);
if (root.isLeaf()) {
print path;
}
else {
for each node of root {
traverse (node, new LinkedList<Node>(path));
}
}
}
答案 1 :(得分:2)
所以基本上你正在进行深度优先搜索,但是不是以非破坏性的方式显式跟踪节点的访问,或者在没有跟踪的情况下保持足够的上下文搜索,你正在破坏树来进行这种跟踪。 / p>
将此转换为普通DFS的传统方法是循环递归条件,基本上将子递归调用更改为:
} else {
for (Node child = node.firstChild(); node != null; node = node.nextChild()) {
traverse(child);
}
}
这将遍历所有孩子,你几乎可以删除node.isLeaf案例,因为回溯是自动完成的。请注意,我编写了nextChild
函数,因为我无法在代码中看到它的内容,但是你必须有类似的东西,或者某种方式来遍历子代。
保留现有代码的更多结构的另一种方法是维护一个包含一组“访问”节点的单独数据结构,如果所有节点名称都是一个字符串,这可能就像一组字符串一样简单unique - 而不是删除节点,将其添加到“visited”集,并且在递归条件下,不检查null,而是查找第一个未访问的节点。这可能比上面的建议更复杂,但可能更类似于你现在拥有的 - 并且在你需要在循环图而不是树上执行此操作时会避免循环。
答案 2 :(得分:1)
我想出了一些在TrieTree中打印单词的东西,可以很容易地适应其他种类的树木或不同的需求:
public void rootToLeaves() {
HashMap<Integer, TrieNode> hashMap = new HashMap<Integer, TrieNode>();
for(TrieNode trieNode : root.getChildren())
rootToLeaves(trieNode, hashMap, 0);
}
private void rootToLeaves( TrieNode trieNode, HashMap<Integer, TrieNode> hashMap, int heightIndex ) {
hashMap.put(heightIndex, trieNode);
if( trieNode.isLeaf() )
printValues(hashMap, heightIndex);
else
for( TrieNode childNode : trieNode.getChildren() )
rootToLeaves( childNode, hashMap, heightIndex + 1 );
}
private void printValues(HashMap<Integer, TrieNode> hashMap, int heightIndex) {
for(int index = 0; index <= heightIndex; index++)
System.out.print(hashMap.get(index).getValue());
System.out.println();
}
此解决方案在内存管理方面做得很好(它使用单个HashMap
,其大小永远不会超过树的高度)并且它提供了很大的灵活性(只需将printValues替换为您需要的任何内容) )。
注意:提前了解树的高度可以让您使用简单的Array
代替Map
。
答案 3 :(得分:0)
1,查找叶节点
2,从叶节点向上遍历
public void printPath(N n) {
if (n == null)
return;
if (n.left == null && n.right == null) {
do {
System.out.print(n.value);
System.out.print(" ");
} while ((n = n.parent) != null);
System.out.println("");
return;
}
printPath(n.left);
printPath(n.right);
}
printPath(根);