如何实现BFS搜索~java

时间:2016-04-02 23:31:01

标签: java breadth-first-search

这是我的代码:

private void doBfs(HiRiQ node, ArrayList<HiRiQ> queue, ArrayList<HiRiQ> path, ArrayList<HiRiQ> visited) {
    while(!queue.isEmpty()){
        HiRiQ current = queue.remove(0);
        if(current.IsSolved()){
            current.print();
            System.out.println("Path found !");
            return;
        } else {    
            if(current.getAllNextStates().isEmpty()){
                return; 
            } else {
                queue.addAll(current.getAllNextStates());
            }
        }
        visited.add(current); 
    }
}

我很难弄清楚如何继续这种方法。我知道如果不访问其他方法它应该很复杂,但我只是想知道这个bfs-search算法中缺少什么。

此bfs搜索的目标应该是找到是否可以从&#34; node&#34;开始找到已解决的配置。

注意:HiRiQ表示拼图板的配置(在这种情况下游戏是pegg-solitaire拼图),方法getAllNextStates()生成所有不同的板配置,这些配置远离当前拼接板。

当我运行它时它没有找到任何解决方案,它无休止地运行。

2 个答案:

答案 0 :(得分:0)

我会给你一个广度优先的想法(因为我觉得你不清楚),因为我们说一个简单的二叉树,这应该让你更清楚。

说这是我们的树。

           1
     /           \
    2             3
  /   \         /   \
4      5       6     7

现在,我们需要进行广度优先搜索,让我们看一下队列数据结构。

queue -> []

让我们在queue

中引用我们的根
queue -> [1]

虽然queue不为空......

- pop the first element, i.e. 1
- if it has a left child, add it to the queue [2]
- if it has a right child, add it to the queue [2,3]
- repeat

这将如何运作?

pop first element, i.e. 1; queue -> []
- if it has a left child, add it to the queue [2]
- if it has a right child, add it to the queue [2,3]

pop first element, i.e. 2; queue -> [3]
- if it has a left child, add it to the queue [3,4]
- if it has a right child, add it to the queue [3,4,5]

pop first element, i.e. 3; queue -> [4,5]
- if it has a left child, add it to the queue [4,5,6]
- if it has a right child, add it to the queue [4,5,6,7]

pop first element, i.e. 4; queue -> [5,6,7]
- if it has a left child, add it to the queue [5,6,7]
- if it has a right child, add it to the queue [5,6,7]

pop first element, i.e. 5; queue -> [6,7]
- if it has a left child, add it to the queue [6,7]
- if it has a right child, add it to the queue [6,7]

pop first element, i.e. 6; queue -> [7]
- if it has a left child, add it to the queue [7]
- if it has a right child, add it to the queue [7]

pop first element, i.e. 7; queue -> []
- if it has a left child, add it to the queue []
- if it has a right child, add it to the queue []

queue is empty

我希望这会清除您的理解并帮助您解决问题。

答案 1 :(得分:0)

正如@DebosmitRay指出的那样,问题可能是你没有检查一个节点是否已被访问过。因此,您的搜索可能会陷入无限循环。

为了帮助您,这是一个用Java实现BFS的粗略框架。你必须自己实现游戏/特定领域的逻辑,例如棋子的配置,测试玩家是否赢了。这可以在State对象中实现:

interface State{
    public List<State> getNeighbors();
    public boolean isGoal();
}

BFS搜索链接到其父状态的状态。此链接可以由类似于以下内容的Node类处理:

class Node {

    private final State state;
    private final Node parent;

    Node(State state, Node parent){
        this.state = state;
        this.parent = parent;
    }

    public Node getParent(){return this.parent;}

    /** 
     * @return a List of neighbor Nodes that can be reached in a single move
     */
    public List<Node> getNeighbors(){
        List<Node> neighbors = new ArrayList<Node>();
        for(State state : state.getNeighbors()){
            neighbors.add(new Node(state,this));
        }
        return neighbors;
    }

    @Override
    public boolean equals(Object o){
        if(this == o) return true;
        if(!(o instanceof Node)) return false;
        Node other = (Node) o;
        return state.equals(other.state); 
    }

    @Override
    public int hashCode(){
        return state.hashCode();
    }

    @Override 
    public String toString(){
        return "Node containing: " + state.toString();
    }

}

BFS逻辑很容易实现:

private void doBfs(State start) {

    List<Node> openList = new  ArrayList<>();
    Set<Node> closedSet = new HashSet<>();

    Node startNode = new Node(start,null);
    openList.add(startNode);

    while (!openList.isEmpty()) {

        Node current = openList.remove(0);

        //If this node has already been visited, skip it
        if(closedSet.contains(current)) continue;


        //check if the current node is a goal (solution) node
        if (current.isGoal()) {

            System.out.println("Path found !");

            //print the path by iterating over the parents
            for(Node parent = current; parent != null; parent = parent.getParent()){
                System.out.println(parent);
            }

            return;
        }

        //Add all neighbors to the openList
        openList.addAll(current.getNeighbors());

        //Add the current node to the closed set so that it is not revisted
        closedSet.add(current);
    }

    System.out.println("No solution could be found from the starting state "+ start);

}