带节点过滤的Java通用树遍历
我有一个通用的树结构。 我需要一个算法来遍历它,如果它们不包含在给定的列表中,则删除一些叶子。如果从子树中删除了所有叶,则也要删除整个子树 示例树:带节点过滤的Java通用树遍历,java,algorithm,tree,tree-traversal,Java,Algorithm,Tree,Tree Traversal,我有一个通用的树结构。 我需要一个算法来遍历它,如果它们不包含在给定的列表中,则删除一些叶子。如果从子树中删除了所有叶,则也要删除整个子树 示例树: 0 / | \ 1 2 3 / \ | / \ 4 5 6 7 8 要保留的叶:{4,6} 结果树: 0 / | 1 2 / | 4 6 输入数据结构包含在HashMap中,其中键是节
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
}
映射节点;
类节点{
私有字符串id;
//其他成员
//能手,二传手
}
我想,某种递归DFS遍历算法应该可以工作,但我找不到它是如何工作的
我想,某种递归DFS遍历算法应该可以工作
完全正确。以下是如何构造此算法:
- 请注意,该任务具有递归结构:将其应用于树的任何分支,对该分支的作用与对整个树的作用相同
- 树枝可以修剪,也可以完全去掉
- 递归实现将返回一个修剪过的分支;它将通过返回
null
- 递归函数将检查传入的
节点
- 如果该节点表示一个叶,则将对照我们希望保留的项目列表检查其内容
- 如果叶不在“保留列表”中,则返回
;否则返回叶子null
- 对于非叶分支,调用递归方法,并检查其结果
- 如果结果为
,则从映射中删除相应的分支;否则,用调用返回的修剪过的分支替换该分支null
- 如果在检查所有分支时,子节点的映射为空,则返回
null
请注意,如果没有叶节点与“keep”列表匹配,则算法可能返回
null
。如果不需要这样做,请在递归实现的顶部添加一个额外的级别,并用返回空树替换顶部级别的返回。我建议您尝试以下方法:
方法boolean removerively(String id,Set leavesToKeep)
将从具有给定id
的节点向下遍历到此分支
首先,我们检查当前节点是否为叶。如果叶不在leavesToKeep
集中,我们将其删除并返回true
,否则返回false
。这是递归的基本情况
如果节点不是叶,则我们执行如下操作:
children.removeIf(n -> removeRecursively(n.id, leavesToKeep));
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;
}
是一个方便的Java8方法,用于删除满足给定谓词的所有元素。这意味着仅当该子项的所有子项也被删除时,该子项才会从列表中删除。因此,如果在子项之后,我们应该使Removery
返回true。removeIf
调用子项
列表为空:
if (children.isEmpty()) {
tree.remove(id);
return true;
} else return false;
完整方法可能如下所示:
children.removeIf(n -> removeRecursively(n.id, leavesToKeep));
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;
}
publicstaticbooleanRemovery(映射树、字符串id、Set-leavestokep){
List children=tree.get(id);
if(children==null | | children.isEmpty()){
如果(!leavestokep.contains(id)){
树。删除(id);
返回true;
}否则返回false;
}
children.removeIf(n->removersively(tree,n.id,leavestokep));
if(children.isEmpty()){
树。删除(id);
返回true;
}否则返回false;
}
其中tree
是您描述的映射,id
是开始节点id,leavesToKeep
是要保留的一组id。带有接口树:
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;
}
}
公共静态接口树{
公共T getValue();
公开儿童名单();
公共默认布尔isLeaf(){
返回子项().isEmpty();
}
公共默认布尔RemoveDeadBranchs(谓词testLiveLeaf){
if(isLeaf()){
返回testLiveLeaf.test(getValue());
}
布尔剩余寿命=假;
for(Iterator it=children().Iterator();it.hasNext();){
if(it.next().RemoveDeadBranchs(testLiveLeaf)){
余生=真;
}否则{
it.remove();
}
}
返老还童;
}
}
导入com.google.common.collect.Lists;
导入org.junit.Before;
导入org.junit.Test;
导入org.slf4j.Logger;
导入org.slf4j.LoggerFactory;
导入java.util.List;
公共类筛选器树节点{
私有记录器Logger=LoggerFactory.getLogger(FilterTreeNode.class);
私有树节点0;
私有列表targetNode=Lists.newArrayList(“B1”、“D1”);
@以前
公共void init(){
node0=TreeNode.builder().nodeCode(“0”).nodeName(“A”).build();
TreeNode1=TreeNode.builder().nodeCode(“1”).nodeName(“B”).build();
TreeNode2=TreeNode.builder().nodeCode(“2”).nodeName(“C”).build();
TreeNode3=TreeNode.builder().nodeCode(“3”).nodeName(“D”).build();
TreeNode4=TreeNode.builder().nodeCode(“4”).nodeName(“B1”).build();
TreeNode5=TreeNode.builder().nodeCode(“5”).nodeName(“B2”).build();
TreeNode6=TreeNode.builder().nodeCode(“6”).nodeName(“C1”).build();
TreeNode7=TreeNode.builder().nodeCode(“7”).nodeName(“D1”).build();
TreeNode8=TreeNode.builder().nodeCode(“8”).nodeName(“D2”).build();
node1.setChildren(list.newArrayList(node4,node5));
node2.setChildren(list.newArrayList(node6));
node3.setChildren(list.newArrayList(node7,node8));
node0.setChildren(list.newArrayList(node1、node2、node3));
}
@试验
公共无效筛选器测试(){
info(“过滤器节点0之前:{}”,节点0);
List retNodes=filterNode(node0);
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;
}