我有一个通用树结构。 我需要一个算法来遍历它,并删除一些叶子,如果它们不包含在给定的列表中。如果从子树中删除了所有叶子,则也删除整个子树。
示例树:
0
/ | \
1 2 3
/ \ | / \
4 5 6 7 8
要留下的叶子:{4,6}
结果树:
0
/ |
1 2
/ |
4 6
输入数据结构包含在HashMap中,其中键是节点的父ID,值是直接在父节点下的节点列表(但不是递归所有子节点)。根节点的父ID是空字符串。
Map<String, List<Node>> nodes;
class Node {
private String id;
//other members
//getters, setters
}
我想,某种递归DFS遍历算法应该可行,但我找不到它,如何。
答案 0 :(得分:2)
我想,某种递归DFS遍历算法应该可以工作
这是完全正确的。以下是构建此算法的方法:
null
Node
null
;否则返回叶子null
,请从地图中删除相应的分支;否则,用通过调用返回的已修剪分支替换分支null
请注意,如果没有叶节点与“keep”列表匹配,则算法可以返回null
。如果这不合适,请在递归实现之上添加额外的级别,并在顶层替换null
返回并返回空树。
答案 1 :(得分:2)
我建议你尝试以下方法:
方法boolean removeRecursively(String id, Set<String> leavesToKeep)
将从具有给定id
的节点遍历到此分支离开。
首先,我们检查一下是不是一片叶子。如果叶子不在leavesToKeep
集合中,我们会将其删除并返回true
,否则返回false
。这是我们递归的基本情况。
如果节点不是叶子,那么我们这样做:
children.removeIf(n -> removeRecursively(n.id, leavesToKeep));
removeIf是一种方便的Java 8方法,用于删除满足给定谓词的所有元素。这意味着只有在删除了所有子项时,才会从列表中删除子项。因此,如果在removeRecursively
调用后children.removeIf
列表为空,我们应该children
返回true:
if (children.isEmpty()) {
tree.remove(id);
return true;
} else return false;
完整方法可能如下所示:
public static boolean removeRecursively(Map<String, List<Node>> tree, String id, Set<String> leavesToKeep) {
List<Node> children = tree.get(id);
if (children == null || children.isEmpty()) {
if (!leavesToKeep.contains(id)) {
tree.remove(id);
return true;
} else return false;
}
children.removeIf(n -> removeRecursively(tree, n.id, leavesToKeep));
if (children.isEmpty()) {
tree.remove(id);
return true;
} else return false;
}
其中tree
是您描述的地图,id
是起始节点ID,leavesToKeep
是要保留的一组ID。
答案 2 :(得分:0)
使用界面树:
public static interface Tree<T> {
public T getValue();
public List<Tree<T>> children();
public default boolean isLeaf() {
return children().isEmpty();
}
public default boolean removeDeadBranches(Predicate<T> testLiveLeaf) {
if (isLeaf()) {
return testLiveLeaf.test(getValue());
}
boolean remainLife = false;
for (Iterator<Tree<T>> it = children().iterator(); it.hasNext();) {
if (it.next().removeDeadBranches(testLiveLeaf)) {
remainLife = true;
} else {
it.remove();
}
}
return remainLife;
}
}
答案 3 :(得分:0)
import com.google.common.collect.Lists;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
public class FilterTreeNode {
private Logger logger = LoggerFactory.getLogger(FilterTreeNode.class);
private TreeNode node0;
private List<String> targetNode = Lists.newArrayList("B1","D1");
@Before
public void init(){
node0 = TreeNode.builder().nodeCode("0").nodeName("A").build();
TreeNode node1 = TreeNode.builder().nodeCode("1").nodeName("B").build();
TreeNode node2 = TreeNode.builder().nodeCode("2").nodeName("C").build();
TreeNode node3 = TreeNode.builder().nodeCode("3").nodeName("D").build();
TreeNode node4 = TreeNode.builder().nodeCode("4").nodeName("B1").build();
TreeNode node5 = TreeNode.builder().nodeCode("5").nodeName("B2").build();
TreeNode node6 = TreeNode.builder().nodeCode("6").nodeName("C1").build();
TreeNode node7 = TreeNode.builder().nodeCode("7").nodeName("D1").build();
TreeNode node8 = TreeNode.builder().nodeCode("8").nodeName("D2").build();
node1.setChildren(Lists.newArrayList(node4,node5));
node2.setChildren(Lists.newArrayList(node6));
node3.setChildren(Lists.newArrayList(node7,node8));
node0.setChildren(Lists.newArrayList(node1,node2,node3));
}
@Test
public void filterTest(){
logger.info("before filter node0: {}",node0);
List<TreeNode> retNodes = filterNode(node0);
if (retNodes.size() >0){
node0.setChildren(retNodes);
}
logger.info("after filter node0: {}",node0);
}
private List<TreeNode> filterNode(TreeNode treeNode){
List<TreeNode> nodes = treeNode.getChildren();
List<TreeNode> newNodes = Lists.newArrayList();
List<TreeNode> tagNodes = Lists.newArrayList();
for(TreeNode node : nodes){
if (targetNode.contains(node.getNodeName())){
newNodes.add(node);
}
if (node.getChildren() != null && node.getChildren().size() >0){
List<TreeNode> retNodes = filterNode(node);
if (retNodes.size()>0){
node.setChildren(retNodes);
}else {
node.setChildren(null);
tagNodes.add(node);
}
}
}
nodes.removeAll(tagNodes);
return newNodes;
}
}
答案 4 :(得分:0)
对于任何寻求与树@Kiril相似的答案而不是地图的人:
树/节点类:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Tree {
private TreeNode node;
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class TreeNode {
private int id;
private boolean isMatch;
private List<TreeNode> nodes;
}
}
和过滤方法:
public Tree filter(Tree tree, List<Integer> ids) {
if (tree.getNode() == null) {
return tree;
}
filterNode(tree.getNode(), ids);
return tree;
}
private boolean filterNode(Tree.TreeNode node, List<Integer> idsToFilter) {
boolean isMatch = idsToFilter.contains(node.getId());
node.setMatch(isMatch);
if (CollectionUtils.isEmpty(node.getNodes()) && !isMatch) {
return true;
}
node.getNodes().removeIf(treeNode -> filterNode(treeNode, idsToFilter));
return node.getNodes().size() == 0 && !isMatch;
}