我在尝试实现A*算法时遇到了这个问题,不知道为什么会出现这个错误:
我的图和启发式函数如下:
我在创建节点时设置了启发式函数的值,并且在创建边时设置了边的值。
以下是代码:
package com.astar.algorithm;import java.util.PriorityQueue;import java.util.HashSet;import java.util.Set;import java.util.List;import java.util.Comparator;import java.util.ArrayList;import java.util.Collections;public class AStar { public static void main(String[] args){ Node s = new Node("S", 12); Node a = new Node("A", 5); Node b = new Node("B", 5); Node c = new Node("C", 5); Node d = new Node("D", 2); Node e = new Node("E", 2); Node f = new Node("F", 1); Node h = new Node("H", 1); Node g = new Node("G", 0); s.adjacencies = new Edge[]{ new Edge(b, 8), new Edge(a, 10) }; b.adjacencies = new Edge[]{ new Edge(d, 8), new Edge(g, 16) }; d.adjacencies = new Edge[]{ new Edge(g, 3), new Edge(h, 1) }; h.adjacencies = new Edge[]{ new Edge(f, 1) }; a.adjacencies = new Edge[]{ new Edge(g, 10), new Edge(c, 2) }; c.adjacencies = new Edge[]{ new Edge(e, 3) }; e.adjacencies = new Edge[]{ new Edge(g, 2) }; AstarSearch(s, g); List<Node> path = printPath(g); System.out.println("Path: " + path); } public static List<Node> printPath(Node target){ List<Node> path = new ArrayList<Node>(); for(Node node = target; node!=null; node = node.parent){ path.add(node); } Collections.reverse(path); return path; } public static void AstarSearch(Node source, Node goal){ Set<Node> explored = new HashSet<Node>(); PriorityQueue<Node> queue = new PriorityQueue<Node>(8, new Comparator<Node>(){ //override compare method public int compare(Node i, Node j){ if(i.f_scores > j.f_scores){ return 1; } else if (i.f_scores < j.f_scores){ return -1; } else{ return 0; } } } ); //cost from start source.g_scores = 0; queue.add(source); boolean found = false; while((!queue.isEmpty())&&(!found)){ //the node in having the lowest f_score value Node current = queue.poll(); explored.add(current); //goal found if(current.value.equals(goal.value)){ found = true; } //check every child of current node for(Edge o : current.adjacencies){ Node child = o.target; double cost = o.cost; double temp_g_scores = current.g_scores + cost; double temp_f_scores = temp_g_scores + child.h_scores; /*if child node has been evaluated and the newer f_score is higher, skip*/ if((explored.contains(child)) && (temp_f_scores >= child.f_scores)) { continue; } /*else if child node is not in queue or newer f_score is lower*/ else if((!queue.contains(child)) || (temp_f_scores < child.f_scores)){ child.parent = current; child.g_scores = temp_g_scores; child.f_scores = temp_f_scores; if(queue.contains(child)){ queue.remove(child); } queue.add(child); } } } }}class Node{ public final String value; public double g_scores; public final double h_scores; public double f_scores = 0; public Edge[] adjacencies; public Node parent; public Node(String val, double hVal){ value = val; h_scores = hVal; } public String toString(){ return value; }}class Edge{ public final double cost; public final Node target; public Edge(Node targetNode, double costVal){ target = targetNode; cost = costVal; }}
回答:
你的程序在向队列中添加节点G时失败了,因为它没有为节点设置任何邻接值。
以下代码尝试添加未分配邻接值的子节点:
queue.add(child);
快速修复方法是修改Node类,并用一个空数组初始化adjacencies,如下所示:
public Edge[] adjacencies = new Edge[]{};
因此,Node类将如下所示:
class Node{ public final String value; public double g_scores; public final double h_scores; public double f_scores = 0; public Edge[] adjacencies = new Edge[]{}; public Node parent; public Node(String val, double hVal){ value = val; h_scores = hVal; } public String toString(){ return value; } }
更好的解决方案是用ArrayList替换数组。