我是学生,我和我的团队必须模拟学生在校园里的行为(比如制作“朋友小组”)走路等。为了找到学生必须去的路径,我使用了A *算法(因为我发现它是最快的寻路算法之一)。不幸的是,我们的模拟不能流畅地运行(在连续迭代之间需要1-2秒)。我想优化算法,但我不知道我能做些什么。如果有可能优化我的A *算法,你们可以帮助我并与我分享信息吗?这里是代码:
public LinkedList<Field> getPath(Field start, Field exit) {
LinkedList<Field> foundPath = new LinkedList<Field>();
LinkedList<Field> opensList= new LinkedList<Field>();
LinkedList<Field> closedList= new LinkedList<Field>();
Hashtable<Field, Integer> gscore = new Hashtable<Field, Integer>();
Hashtable<Field, Field> cameFrom = new Hashtable<Field, Field>();
Field x = new Field();
gscore.put(start, 0);
opensList.add(start);
while(!opensList.isEmpty()){
int min = -1;
//searching for minimal F score
for(Field f : opensList){
if(min==-1){
min = gscore.get(f)+getH(f,exit);
x = f;
}else{
int currf = gscore.get(f)+getH(f,exit);
if(min > currf){
min = currf;
x = f;
}
}
}
if(x == exit){
//path reconstruction
Field curr = exit;
while(curr != start){
foundPath.addFirst(curr);
curr = cameFrom.get(curr);
}
return foundPath;
}
opensList.remove(x);
closedList.add(x);
for(Field y : x.getNeighbourhood()){
if(!(y.getType()==FieldTypes.PAVEMENT ||y.getType() == FieldTypes.GRASS) || closedList.contains(y) || !(y.getStudent()==null))
{
continue;
}
int tentGScore = gscore.get(x) + getDist(x,y);
boolean distIsBetter = false;
if(!opensList.contains(y)){
opensList.add(y);
distIsBetter = true;
}else if(tentGScore < gscore.get(y)){
distIsBetter = true;
}
if(distIsBetter){
cameFrom.put(y, x);
gscore.put(y, tentGScore);
}
}
}
return foundPath;
}
private int getH(Field start, Field end){
int x;
int y;
x = start.getX()-end.getX();
y = start.getY() - end.getY();
if(x<0){
x = x* (-1);
}
if(y<0){
y = y * (-1);
}
return x+y;
}
private int getDist(Field start, Field end){
int ret = 0;
if(end.getType() == FieldTypes.PAVEMENT){
ret = 8;
}else if(start.getX() == end.getX() || start.getY() == end.getY()){
ret = 10;
}else{
ret = 14;
}
return ret;
}
// EDIT
这是我从jProfiler获得的:
所以getH是瓶颈吗?也许记住场上的H得分会是一个好主意吗?
答案 0 :(得分:6)
您可以使用不同的算法优化问题,以下页面说明并比较了许多不同的算法和启发式方法:
答案 1 :(得分:6)
链接列表不是开放集的良好数据结构。您必须从中找到具有最小F的节点,您可以在O(n)中搜索列表,也可以在O(n)中的有序位置插入,无论哪种方式都是O(n)。使用堆只有O(log n)。更新G分数将保持为O(n)(因为您必须先找到节点),除非您还从节点向堆中的索引添加了HashTable。
链接列表也不是封闭集的良好数据结构,您需要快速“包含”,即链接列表中的O(n)。你应该使用HashSet。
答案 2 :(得分:2)
从您的实现看来,您似乎正在使用天真的A *算法。使用以下方式: -
A *是使用类似于BFS的优先级队列实现的算法。
在每个节点评估启发式函数,以定义其适合作为下一个要访问的节点的适合度。
当访问新节点时,其相邻的未访问节点将以其启发式值作为键添加到队列中。
- 醇>
这样做直到队列中的每个启发式值小于(或大于)目标状态的计算值。
答案 3 :(得分:1)
答案 4 :(得分:1)
a)如上所述,您应该在A *中使用堆 - 基本二进制堆或配对堆,理论上应该更快。
b)在较大的地图中,总是需要一些时间让算法运行(即,当您请求路径时,它只需要花费一些时间)。可以做的是在路径计算时使用一些本地导航算法(例如,“直接运行到目标”)。
c)如果您有合理数量的位置(例如,在导航网格中)和代码开头的某个时间,为什么不使用Floyd-Warshall的算法?使用它,您可以在O(1)中找到下一步的信息。
答案 5 :(得分:0)
我构建了一个新的寻路算法。称为Fast *或Fastaer,它是像A *一样的BFS,但比A *更快更有效,准确度为90%A *。请参阅此链接以获取信息和演示。
https://drbendanilloportfolio.wordpress.com/2015/08/14/fastaer-pathfinder/
它有一个快速贪婪的线描示器,使路径更直。 演示文件拥有一切。使用演示进行性能指标时检查任务管理器。到目前为止,在构建此结果时,其分析结果具有最大存活生成4和低至零GC时间。