Java - 使用节点迭代加深搜索

时间:2014-02-21 03:23:52

标签: java search

我正在设计一个程序,用于搜索二维数字数组,这些数字表示指向指定终点的路径的地图。我一直在使用具有多个参数的节点,最突出的是相邻的北,南,东和西节点,每个节点代表地图中的正方形。我目前正在尝试完成的搜索方法是迭代加深,但每次尝试运行程序时,我都会遇到堆栈溢出错误。这是迭代深化课程。

import java.util.*;
import java.io.*;
public class IDeepeningSearch {
    private Node start;
    private Node end;
    private int[][] map;
    private ArrayList<Node> solution;

    //Build using file handler
    public IDeepeningSearch(String file){
        FileHandler handle = new FileHandler(file);

        //Create map
        map = handle.getMap();

        //Start node coordinates and value
        start = new Node();
        start.setRow(handle.getSRow());
        start.setCol(handle.getSCol());
        start.setValue(map[start.getRow()][start.getCol()]);

        //End node coordinates
        end = new Node();
        end.setRow(handle.getERow());
        end.setCol(handle.getECol());
        end.setValue(map[start.getRow()][start.getCol()]);
    }

    //Runs search
    public void run(){
        int i = 0;
        solution = new ArrayList<Node>();
        //Value of i indicates depth to be explored; will increment with each failure
        while(solution.isEmpty()){
            search(start, i);
            i++;
        }
        if(!solution.isEmpty()){
            System.out.println("It worked.");
        }
        System.out.println("If you're not seeing the other message then it failed.");
    }

    //Building tree
    public void build(Node head){
        setNLeaf(head);
        setSLeaf(head);
        setELeaf(head);
        setWLeaf(head);
//      if(head.getNorth() != null){
//          build(head.getNorth());
//      }
//      if(head.getSouth() != null){
//          build(head.getSouth());
//      }
//      if(head.getEast() != null){
//          build(head.getEast());
//      }
//      if(head.getWest() != null){
//          build(head.getWest());
//      }
    }

    //Performs search
    public void search(Node head, int depth){
        if(head.getRow() == end.getRow() && head.getCol() == end.getCol()){
            solution.add(head);
            return;
        }
        else{
            if(depth == 0){
                return;
            }
            build(head);
            if(head.getNorth() != null){
                search(head.getNorth(), depth--);
            }
            if(head.getSouth() != null){
                search(head.getSouth(), depth--);
            }
            if(head.getEast() != null){
                search(head.getEast(), depth--);
            }
            if(head.getWest() != null){
                search(head.getWest(), depth--);
            }
        }
    }

    //Sets north leaf
    public void setNLeaf(Node node){
        //Determines if parent is on edge of map and if desired space has 0 value
        if(node.getRow() != 0 && map[node.getRow() - 1][node.getCol()] != 0){
            Node n = new Node();
            n.setRow(node.getRow() - 1);
            n.setCol(node.getCol());
            n.setValue(map[n.getRow()][n.getCol()]);
            n.setParent(node);
            node.setNorth(n);
        }
    }

    //Sets south leaf
    public void setSLeaf(Node node){
        //Determines if parent is on edge of map and if desired space has 0 value
        if(node.getRow() != (map.length - 1) && map[node.getRow() + 1][node.getCol()] != 0){
            Node n = new Node();
            n.setRow(node.getRow() + 1);
            n.setCol(node.getCol());
            n.setValue(map[n.getRow()][n.getCol()]);
            n.setParent(node);
            node.setSouth(n);
        }
    }

    //Sets east leaf
    public void setELeaf(Node node){
        //Determines if parent is on edge of map and if desired space has 0 value
        if(node.getRow() != (map[0].length - 1) && map[node.getRow()][node.getCol() + 1] != 0){
            Node n = new Node();
            n.setRow(node.getRow());
            n.setCol(node.getCol() + 1);
            n.setValue(map[n.getRow()][n.getCol()]);
            n.setParent(node);
            node.setEast(n);
        }
    }

    //Sets west leaf
    public void setWLeaf(Node node){
        //Determines if parent is on edge of map and if desired space has 0 value
        if(node.getCol() != 0 && map[node.getRow()][node.getCol() - 1] != 0){
            Node n = new Node();
            n.setRow(node.getRow());
            n.setCol(node.getCol() - 1);
            n.setValue(map[n.getRow()][n.getCol()]);
            n.setParent(node);
            node.setWest(n);
        }   
    }
}

我以为我正确地做到了这一点,但我所得到的错误一直都很稳定。这就是我最终的目标。

Exception in thread "main" java.lang.StackOverflowError
at Node.setSouth(Node.java:88)
at IDeepeningSearch.setSLeaf(IDeepeningSearch.java:113)
at IDeepeningSearch.build(IDeepeningSearch.java:48)
at IDeepeningSearch.search(IDeepeningSearch.java:75)
at IDeepeningSearch.search(IDeepeningSearch.java:77)
at IDeepeningSearch.search(IDeepeningSearch.java:80)
at IDeepeningSearch.search(IDeepeningSearch.java:77)

倒数第二行和最后一行重复。我已经尝试构建一个完整的树,但要么给我另一个堆栈溢出错误或空指针异常。我不确定这里的问题是什么,但如果我能解决这个问题,我相信我也可以完成我的广度优先搜索方法。

2 个答案:

答案 0 :(得分:1)

depth--评估depth的原始值。这意味着未修改的depth版本将被传递给search()的递归调用,因此您的代码永远不会接近基本情况。请尝试使用depth-1。或者,如果您需要更改局部变量深度的值,--depth

例如,这将持续打印10直到达到堆栈溢出

public void foo(int x) {
    if (x == 0) {
        return;
    }
    System.out.println(x);
    foo(x--);
}

foo(10);

答案 1 :(得分:0)

StackOverflowError是因为Chris Rise在答案中提到的search(node, depth--)的有问题的递归调用。请尝试--depth来解决此问题。

此代码中的内存管理也很差,这会浪费堆内存,这可能会因为多次调用GC(Garbage-Collector)而导致程序变慢或导致OutOfMemeoryError!每次创建setXLeaf(Node n)时,setNLeaf(Node north)方法(例如new Node等)都会显示此问题,而只有在需要进行简单检查时才能执行此操作:< / p>

if (node.getSouth() == null) {
    Node n = new Node();
    n.setParent(node);
    node.setSouth(n);
}
node.getSouth().setRow(node.getRow() + 1);
node.getSouth().setCol(node.getCol());
node.getSouth().setValue(map[node.getRow() + 1][node.getCol()]);

这样您就可以避免创建不必要的新对象。这应该在所有setXLeaf(...)方法中修复。