在BFS中进行目标检查

时间:2017-07-04 10:13:43

标签: java breadth-first-search

我尝试在JAVA中根据我学习的内容实现BFS算法,但我有点困惑,我不确定我是否正在检查节点是否是目标还是我正在添加节点来探索列表中的适当的地方。这是代码:

frontier.add(nodes.getFirst());//node.isGoal is only true if the node is desired node
    if(frontier.getFirst().isGoal)//Checking if the root node is goal
    {
        explored.add(frontier.getFirst());
        prev.put(frontier.getFirst(), null);
        goalNode = explored.getFirst();
        frontier.poll();
    }
    while (!frontier.isEmpty())
    {
        currentNode = frontier.poll();
        explored.add(currentNode);
        for (Node node : currentNode.children) {//adding node children to fronier and checking if they are goal
            if (!frontier.contains(node) || !explored.contains(node)) {
                frontier.add(node);
                prev.put(node, currentNode);//mapping nodes to parent node to return sequence of nodes
                if (node.isGoal) {
                    goalNode = node;
                    break;
                }
            }
        }
    }

提前致谢。

1 个答案:

答案 0 :(得分:1)

根据我对你的代码的理解,你似乎做错了:你检查初始集中的第一个节点(例如树级),如果它不是目标节点,你添加任何不是的子节点已经在frontier但还没有访问过。那没关系,但可能没必要。在检查任何父母的兄弟姐妹之前,你检查孩子是错误的,这样你的搜索就不是那么广泛。

那么你能做什么/应该做什么?

假设您的数据代表树(广度优先表示),并且您在某个级别(例如根节点)开始。由于数据是广度优先的树,任何孩子都不能被访问,也可能不在您的frontier列表中,因此无需检查(如果您有可能不是这种情况的更一般的图表。

因此算法看起来像这样:

LinkedList<Node> frontier = new LinkedList<>();

//assuming you always have a root node just add it
frontier.add( root );

Node goal = null;

//loop until the list is empty, if we found a goal node we'll break the loop from the inside
while( !frontier.isEmpty() ) {
  //get the node at the start of the list and remove it
  //in the first iteration this will be the root node
  Node node = frontier.pop();

  //found a goal so we're done
  if( node.isGoal ) {
    goal = node ;        
    break; //this breaks the while loop
  }

  //didn't find a goal yet so add the children at the end
  if( node.children != null ) {
    frontier.addAll( node.children );
  }
}

这样做意味着你在最后添加下一级节点(子节点),然后从前面弹出树上方的节点,直到找到你正在搜索的内容。这意味着您应该始终在列表中只有一个或两个级别的树,即当前级别以及任何已处理的当前级别节点的直接子级。

正如您还可以看到,因为我们在树上操作,所以无需保留explored设置。

此外,您可能想要考虑是否确实需要在迭代期间构建prev映射,因为您可能必须再次删除元素,并且映射不太适合从目标节点到达目标节点的路径根。您可能希望在每个节点中保留指向父节点的链接,因此,一旦找到了目标节点,您就会迭代直到到达根节点。