TL;博士
从结构来看,您在List 中提供的每个Node 是根一个N-ary 树数据结构(我假设没有圆圈)。
为了获得所需的数据,我们可以使用经典的tree-traversal algorithms 之一。平均深度小于平均宽度时深度优先搜索算法会更合适,因为它会更节省空间,在相反的情况下使用会更好广度优先搜索.我会选择 DFS。
提出递归实现更容易,所以我将从它开始。但它有不Java 中的实用价值,因此我们将继续进行一些改进。
流+递归
您可以创建一个辅助方法来负责展平将从流中调用的节点。
List<Node> nodes = // initializing the list
long totalScore = nodes.stream()
.flatMap(node -> flatten(node).stream())
.filter(Node::isSelected)
.mapToLong(Node::getScore)
.sum();
递归辅助方法:
public static List<Node> flatten(Node node) {
if (node.getSubNodes().isEmpty()) {
return List.of(node);
}
List<Node> result = new ArrayList<>();
result.add(node);
node.getSubNodes().forEach(n -> result.addAll(flatten(n)));
return result;
}
没有递归
避免StackOverflowError方法flatten()可以实现没有通过轮询和分配新的递归节点在堆栈上(由ArrayDeque 表示)迭代。
public static List<Node> flatten(Node node) {
List<Node> result = new ArrayList<>();
Deque<Node> stack = new ArrayDeque<>();
stack.add(node);
while (!stack.isEmpty()) {
Node current = stack.poll();
result.add(current);
current.getSubNodes().forEach(stack::push);
}
return result;
}
无递归和无中间数据分配
以以下形式分配中间数据节点最终不会被使用是不切实际的。
相反,我们可以让辅助方法负责计算总得分通过汇总每个分数产生选定节点在里面节点树.
为此,我们需要在遍历树时执行isSelected()。
List<Node> nodes = // initializing the list
long totalScore = nodes.stream()
.mapToLong(node -> getScore(node))
.sum();
public static long getScore(Node node) {
long total = 0;
Deque<Node> stack = new ArrayDeque<>();
stack.push(node);
while (!stack.isEmpty()) {
Node current = stack.poll();
if (current.isSelected()) total += current.getScore();
current.getSubNodes().forEach(stack::push);
}
return total;
}