我有一个简单的分支界限算法,可以处理旅行商问题的一种变体,我想尝试将其转化为使用Java 8 Stream API。然而,在不依赖副作用的情况下进行转换时,我遇到了一些困难。
初始代码
int bound = Integer.MAX_VALUE;
List<Location> bestPath = null;
while(!queue.isEmpty()) {
Node curr = queue.poll();
//bound exceeds best, bail
if (curr.getBound() >= bound) {
return bestPath;
}
//have a complete path, save it
if(curr.getPath().size() == locations.size()) {
bestPath = curr.getPath();
bound = curr.getBound();
continue;
}
//incomplete path - add all possible next steps
Set<Location> unvisited = new HashSet<>(locations);
unvisited.removeAll(curr.getPath());
for (Location l : unvisited) {
List<Location> newPath = new ArrayList<>(curr.getPath());
newPath.add(l);
Node newNode = new Node(newPath, getBoundForPath(newPath));
if (newNode.getBound() <= bound){
queue.add(newNode);
}
}
}
我来尝试使用 Stream API 进行转换,并得出以下结果: Java 8 版本
Consumer<Node> nodeConsumer = node -> {
if(node.getPath().size() == locations.size() ) {
bestPath = node.getPath();
bound = node.getBound();
} else {
locations.stream()
.filter(l -> !node.getPath().contains(l))
.map(l -> {
List<Location> newPath = new ArrayList<>(node.getPath());
newPath.add(s);
return new Node(newPath, getBoundForPath(newPath));
})
.filter(newNode -> newNode.getBound() <= bound)
.forEach(queue::add);
}
};
Stream.generate(() -> queue.poll())
.peek(nodeConsumer)
.filter(s -> s.getBound() > bound)
.findFirst();
return bestPath;
主要问题在于nodeConsumer必须引用bestPath和bound,而它们不是final变量。我可以将它们作为final AtomicReference变量来解决此问题,但我觉得这有点违反了流API的精神。是否有人可以帮助我将初始算法简化为更符合惯用法的实现方式?