【问题标题】:Element appears magically in PriorityQueue?元素神奇地出现在 PriorityQueue 中?
【发布时间】:2017-02-02 18:26:03
【问题描述】:

代码说明: 因此,我正在为 ASCII 映射实现 A* 最短路径算法,其中可传递的字段位于数组 (map[][]) 中。 我有一个 PriorityQueue,以及两个用于 Dijkstra 距离 (d) 和启发式 (h) 的 HashMap,它们分别使用伪无穷大和欧几里得距离进行初始化。

相关的while循环获取优先队列的元素u,然后与邻居v检查是否可以更好地距离。

我的问题: 在标记的行中,在 d 中找不到 v(对于 v=(171,434)),所以我得到一个空指针异常,尽管对于队列的每个元素在 d 和 h 中都有一个初始化值。正如您在注释行中看到的那样,我检查它 (171,434) 是否被添加到优先级队列中,但它没有,但它以某种方式通过了上面的 if 子句。知道它是如何潜入的吗?

Map<Point, Double> aStar(Point start, Point end){
    Map<Point, Double> d = new HashMap<Point, Double>();
    Map<Point, Double> h = new HashMap<Point, Double>();
    PriorityQueue<Point> queue = new PriorityQueue<Point>(fieldCount,new AStarComparator(d,h));
    for(int i=0;i<map.length;i++){
        for(int j=0;j<map[i].length;j++) {
            Point p = new Point(i,j);
            if(!p.equals(start) && map[i][j]) {
                d.put(p, Double.MAX_VALUE);
                h.put(p, p.distance(end));
                queue.add(p);
                //if(p.equals(new Point(171,434)))
                //  System.out.println("Added " + p + " with d = " + d.get(p));
            }
        }
    }
    d.put(start, 0.0);
    h.put(start, start.distance(end));
    queue.add(start);
    //System.out.println("Added " + start + " with d = " + d.get(start));

    while(!queue.isEmpty()){
        System.out.println("Polling " + queue.peek());
        Point u = queue.poll();
        Point v = new Point();
        for(int i= -1; i <= +1; i++) {
            for(int j= -1; j <= +1; j++) {
                v.x = u.x + i;
                v.y = u.y + j;

                if(queue.contains(v)){
-->                 System.out.println("u = " + u + ", v = " + v + ", d.get(v) = " + d.get(v) + ", d.contains(v) = " + d.containsKey(v));**
                    double weight = (i == 0 || j == 0) ? 1 : Math.sqrt(2);
-->                 if(d.get(u) + weight < d.get(v)) {
                        d.put(v, d.get(u) + weight);
                        //refresh queue
                        queue.remove(v);
                        queue.add(v);
                        System.out.println("Refreshing with " + v);
                    }
                }
            }
        }
    }
    return d;
}

编辑:

Stacktrace(其中 117 是 if 子句的行):

java.lang.NullPointerException
at StarcraftShortestPath.aStar(StarcraftShortestPath.java:117)
at StarcraftShortestPath.findPath(StarcraftShortestPath.java:141)
at StarcraftTest.test1stRoute(StarcraftTest.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

【问题讨论】:

  • 请跟踪堆栈。在 println() 调用中获得 NPE 的唯一方法是 d 为空。
  • 您是否正确覆盖了您的点类中的hashcodeequals
  • @EJP 我在 if 子句中得到了 NPE,我认为这是因为 d.get(v) 为空,我在 print() 中注意到了这一点。
  • @EJP 在 if 条件中解开 Double 会导致 NullPointerException。
  • @Calculator 是 java.awt.Point 类

标签: java queue priority-queue a-star


【解决方案1】:

删除然后添加相同的东西没有任何效果。这是一个错误。您应该在更新之前删除v,然后再添加它。

还有第二个错误:您必须每次在内循环周围使用一个新的v。如果您使用相同的v,您将在不告知 PQ 的情况下对其进行更新,如果根据这些值对 PQ 进行排序,则会损坏 PQ。

【讨论】:

  • 哇,谢谢。这就是您尝试节省新对象分配的结果。但是,就我所见,重新排序队列操作并没有改变任何东西,所以我不确定这是否是一个“错误”,这不是更像是一种不好的做法吗?
  • 无论是无意义的还是令人讨厌的练习,不确定哪个因为我不知道算法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-21
  • 2014-04-09
  • 2014-08-04
相关资源
最近更新 更多