我有一个通用的树结构 . 我需要一个算法来遍历它,并删除一些叶子,如果它们不包含在给定的列表中 . 如果从子树中删除了所有叶子,则也删除整个子树 .
示例树:
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遍历算法应该可行,但是我找不到它,怎么做 .
4 回答
我建议你尝试以下方法:
方法
boolean removeRecursively(String id, Set<String> leavesToKeep)
将从具有给定id
的节点遍历到此分支离开 .首先,我们检查一下是不是一个叶子 . 如果叶子不在
leavesToKeep
集合中,我们将其删除并返回true
,否则返回false
. 这是我们递归的基本情况 .如果节点不是叶子,那么我们这样做:
removeIf是一种方便的Java 8方法,用于删除满足给定谓词的所有元素 . 这意味着只有在删除了所有子项时,才会从列表中删除子项 . 因此,如果
children.removeIf
调用children
列表为空,我们应该使removeRecursively
返回true:完整方法可能如下所示:
其中
tree
是您描述的 Map ,id
是起始节点ID,leavesToKeep
是要保留的一组ID .这是完全正确的 . 以下是构建此算法的方法:
观察任务是否具有递归结构:将其应用于树的任何分支对分支执行与您想要对整个树执行的操作相同的操作
分支可以被修剪,也可以完全删除
您的递归实现将返回一个已修剪的分支;它会通过返回
null
来指示删除分支递归函数会检查传入
Node
如果节点表示叶子,则将根据我们希望保留的项目列表检查其内容
如果"keep list"上没有叶子,则返回
null
;否则返回叶子对于非叶子分支,调用递归方法,并检查其结果
如果结果为
null
,则从 Map 中删除相应的分支;否则,用从调用返回的修剪分支替换分支如果检查所有分支时子节点的映射为空,则返回
null
请注意,如果没有叶节点与"keep"列表匹配,则算法可以返回
null
. 如果这不合适,请在递归实现之上添加额外的级别,并在返回空树的情况下替换顶层的null
返回 .使用界面树: