【问题标题】:ArrayIndexOutOfBoundsException on generating maze graph with depth first search [duplicate]使用深度优先搜索生成迷宫图时的 ArrayIndexOutOfBoundsException [重复]
【发布时间】:2016-02-02 02:54:06
【问题描述】:

我创建了一个程序来解决读取文本文件输入的迷宫问题。我设法使用深度优先搜索来解决它,结果在这样的小迷宫上很好:

11 3
2 3
0 3
1 4
5 4
5 7
6 7
7 8
8 9
9 10
0 5

解决中小型迷宫的一切都很好,但是当迷宫变大时,它会给我一个 ArrayIndexOutOfBoundsException 错误(见下文)。

Enter maze file: test2.txt
Enter start node: 0
Enter goal node: 1
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 207
    at MazeGraph.addArc(MazeGraph.java:95)
    at MazeGraph.<init>(MazeGraph.java:51)
    at MazeSystem.<init>(MazeSystem.java:25)
    at MazeSystem.main(MazeSystem.java:37)
Java Result: 1

我的程序应该会自动读取 test2.txt(这是大迷宫文件)文件中有多少节点,但发生了这个错误。代码如下所示:

MazeGraph.java

import java.io.*;
import static java.lang.System.out;
import java.util.*;

/**
 * This class creates a representation of Maze as a Graph by reading from a text
 * file.
 *
 * @author Muhammad
 */
public class MazeGraph {

    final int node; //For declaring constant value of a node.
    int arc;
    List<Integer>[] adjacencyList;
    static Set<Integer> setOfNodes = new HashSet<>();
    private static Scanner scanNodeSize;

    /**
     * This constructors takes an integer parameter for reading node indexes in
     * a list of adjacent nodes.
     *
     * @param node - integer parameter for passing the nodes value from the file
     * and create a list of adjacent nodes.
     */
    MazeGraph(int node) {
        this.node = node;
        this.arc = 0;//initialise to empty arcs
        adjacencyList = (List<Integer>[]) new List[node];
        for (int index = 0; index < node; index++) {
            adjacencyList[index] = new LinkedList<Integer>();
        }
    }

    /**
     * The main constructor that takes a String parameter for reading maze file.
     *
     * @param mazeFile
     */
    public MazeGraph(String mazeFile) {
        this(getNodeSize(mazeFile));
        Scanner scan;
        try {
            //Scan maze file.
            scan = new Scanner(new File(mazeFile));
            /*loop when it has next integer then read two nodes from the file and add arc for it.*/
            while (scan.hasNextInt()) {
                int node1 = scan.nextInt();
                int node2 = scan.nextInt();
                addArc(node1, node2);
            }
        } catch (FileNotFoundException ex) {
            out.println(ex.getMessage());
        }
    }

    /**
     * This method returns a size of the set of nodes by taking a String
     * parameter which the name of the maze file.
     *
     * @param mazeFile - String parameter for reading maze file for scanning the
     * size of the nodes.
     * @return - returns an integer value for the size of the set of nodes.
     */
    public static int getNodeSize(String mazeFile) {

        try {
            scanNodeSize = new Scanner(new File(mazeFile));
            while (scanNodeSize.hasNextInt()) {
                int node1 = scanNodeSize.nextInt();
                int node2 = scanNodeSize.nextInt();
                setOfNodes.add(node1);
                setOfNodes.add(node2);
            }
            return setOfNodes.size();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return setOfNodes.size();

    }

    /**
     * This method adds an arc by adding two different nodes in array of list
     * called adjacency list.
     *
     * @param node1 - first node.
     * @param node2 - next node.
     */
    private void addArc(int node1, int node2) {
        arc++; //Increase arc by one whenever this addArc method is called.
        adjacencyList[node1].add(node2);
        adjacencyList[node2].add(node1);

    }

    //Print the nodes and its arcs by looping through the adjacency list.
    public void print() {
        out.println(node + " Nodes, " + arc + " Arcs \n");
        for (int fromNode = 0; fromNode < node; fromNode++) {
            out.print(fromNode + " connected to ");
            for (int arcNode : adjacencyList[fromNode]) {
                out.print(arcNode + " ");
            }
            out.println();
        }
    }

    /**
     * This method returns a list of nodes to allow objects to be the target for
     * "for-each" statement in order to iterate through the nodes.
     *
     * @param nodes - an Integer parameter for getting the number of nodes in a
     * list.
     * @return - returns a list of nodes.
     */
    public Iterable<Integer> getAdjacencyList(int nodes) {
        return adjacencyList[nodes];
    }
}

在 MazeGraph.java 中,getNodeSize 方法返回一个整数,用于构造函数的参数。为了使它工作,我必须在构造函数的参数中取出那个 getNodeSize 方法,而是在那里放一些更大的值,例如 300。在堆栈跟踪中,它说问题出在 addArc 方法中。如果它已经在其他迷宫中工作,我试图弄清楚如何解决这个问题,以便它也可以自动在大型迷宫中读取。请,如果有人能解决这个问题,我将不胜感激。

这是大文件。

0 2
0 3
0 200
201 202
202 203
203 204
204 205
205 206
206 207
207 208
208 209
209 210
210 211
211 212
212 213
213 214
214 215
215 216
216 217
217 218
218 219
219 1
185 122
7 134
15 161
65 165
34 13
22 73
173 189
21 149
204 71
159 148
66 97
122 125
35 63
78 54
147 84
184 183
80 203
125 2
80 111
125 72
166 121
145 151
51 140
74 152
116 46
138 202
114 9
127 133
177 128
202 138
94 122
30 30
32 117
125 16
157 16
187 150
129 37
55 3
53 118
202 185
187 185
155 174
79 107
159 33
143 18
6 90
74 59
161 67
82 57
77 127
123 204
38 96
114 150
92 137
35 136
118 79
154 140
109 203
178 72
13 204
58 6
8 28
98 42
137 123
59 95
162 69
22 142
68 91
155 90
117 90
143 103
43 73
153 28
152 106
160 187
42 171
15 154
84 151
163 97
7 126
12 28
31 95
71 63
37 110
189 128
98 115
143 185
124 187
73 194
58 19
192 100
133 93
105 39
124 191
126 143
136 34
44 182
199 168
110 202
20 169
180 64
87 166
204 159
110 125
122 4
105 112
90 11
124 138
196 89
179 114
184 70
38 30
62 68
26 34
203 55
204 60
49 173
107 90
37 180
156 92
196 170
193 107
70 110
68 133
61 132
176 125
180 203
160 165
160 95
204 21
81 78
25 133
74 49
199 111
12 62
203 165
53 81
33 190
122 38
86 170
45 127
75 117
113 88
138 189
177 176
43 141
179 80
24 166
121 126
12 122
94 74
106 16
176 126
93 72
153 184
202 111
19 13
30 106
73 116
149 202
191 32
16 37
66 23
5 50
115 104
149 189
72 52
31 69
111 164
135 147
109 142
94 167
196 12
75 121
64 201
11 96
183 171
117 96
87 10
188 36
89 141
156 84
52 24
167 58
67 102
35 129
73 84
191 45
12 102
100 33
66 30
96 140
82 195
61 202
144 175
41 35
140 123
144 150
194 102
14 29
161 84
198 155
188 190
161 48
197 75
132 160
65 89
115 84
104 46
85 155
35 181
73 11
76 68
116 137
170 177
16 101
151 189
191 201
33 37
81 5
153 135
85 121
147 12
49 186
98 171
43 27
123 131
9 19
19 205
79 192
197 159
94 22
203 153
7 83
20 195
179 21
125 183
156 65
92 104

【问题讨论】:

  • 您是否验证了迷宫文件?可能是迷宫文件本身有错误,而不是您的代码。
  • 如果你可以在描述中看到,我可以更改节点数,迷宫文件就可以了。
  • 你能把大迷宫文件贴在某个地方吗?
  • 我已经在我的描述中添加了。检查上面。谢谢。
  • 在下面查看我的答案。这些更改适用于您在上面提供的文件。

标签: java artificial-intelligence depth-first-search undirected-graph


【解决方案1】:

好的,问题出在getNodeSize(String)。你返回setOfNodes.size()。问题是如果一个节点是一个单例(即它没有连接弧),那么它不会在迷宫文件中列出。例如,假设您的迷宫文件是“9999 1”,仅此而已。然后您的getNodeSize() 方法将返回 2。然后您的代码将节点数组实例化为大小为 2。然后您尝试在 9999 和 1 之间添加一个弧,但收到一个 ArrayIndexOutOfBoundsException,因为数组中只有两个位置,但是您正在尝试索引位置 9999。

相反,您应该返回观察到的最大节点 ID 加一。下面的代码实现了这一点:

/**
 * This method returns a size of the set of nodes by taking a String
 * parameter which the name of the maze file.
 *
 * @param mazeFile - String parameter for reading maze file for scanning the
 * size of the nodes.
 * @return - returns an integer value for the size of the set of nodes.
 * @throws FileNotFoundException if the mazeFile could not be found
 */
public static int getNodeSize(String mazeFile) throws FileNotFoundException{
        scanNodeSize = new Scanner(new File(mazeFile));
        while (scanNodeSize.hasNextInt()) {
            int node1 = scanNodeSize.nextInt();
            int node2 = scanNodeSize.nextInt();
            setOfNodes.add(node1);
            setOfNodes.add(node2);
        }

        //Changes begin here
        Integer max = setOfNodes.stream().reduce(Integer::max).get();
        return max+1;
        //Changes end here

}

注意:我删除了 try-catch 块并将其替换为 throws 声明。

更好的方法:通常不赞成将数组和Collection 混合使用。使用HashMap 可能会更好:

HashMap<Integer,List<Integer>> adjacencyList = new HashMap<>();

您可以通过调用adjacencyList.get(nodeId) 访问任何节点的邻接列表,并且您的构造函数可以更改为:

public MazeGraph(String mazeFile) {
    adjacencyMap = new HashMap<>();
    Scanner scan;
    try {
        //Scan maze file.
        scan = new Scanner(new File(mazeFile));
        /*loop when it has next integer then read two nodes from the file and add arc for it.*/
        while (scan.hasNextInt()) {
            int node1 = scan.nextInt();
            int node2 = scan.nextInt();
            List<Integer> node1AdjList = adjacencyMap.getOrDefault(node1,new LinkedList<Integer>());
            List<Integer> node2AdjList = adjacencyMap.getOrDefault(node2,new LinkedList<Integer>());
            node1AdjList.add(node2);
            node2AdjList.add(node1);
            adjacencyMap.put(node1, node1AdjList);
            adjacencyMap.put(node2, node2AdjList);
        }
    } catch (FileNotFoundException ex) {
        out.println(ex.getMessage());
    }
    node = adjacencyMap.keySet().parallelStream().reduce(Integer::max).get();

}

【讨论】:

  • 你的 jdk 7 代码的另一个版本是什么,因为目前我使用的系统是 jdk 7,所以基本上我无法让它工作,因为我认为你的代码在 jdk 8 中,如果这对你来说很有意义。谢谢。
  • 另外,你为什么要在构造函数中放另一个布尔参数?你把它用在什么地方了?不知道你在哪里用过,估计是保存删除吧。
  • 那是我测试方法的产物;你可以删除它。我相应地编辑了我的答案。
  • 既然你用 jdk 8 解决了,我决定将源代码更改为 jdk 8 并且它可以工作!!非常感谢..你解决了我的问题..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多